Great work man, Appreciate the effort, one question please if i may, is there a way to localize the exception message throwen?, if not .. does the throwed exceptions have a unique underline number(similer to SQL Server error messages numberd) so i can localize it, thank you in advance.
A question about code quality and maintainability: in the default use case like "name.Throw()..." it uses System.ArgumentException by default. For long term readability and maintainability, would you code so that you specify the exception always, even though redundant in the current state of the project (eg, use "name.Throw(paramName => throw new System.ArgumentException($"Param name: {paramName}."))")? The question comes from it not being clear which exception will be thrown just from reading the code. I had to look at the docs in order to know what the default exception type was. Also, some checks throw different exceptions based on the type of check you are doing (eg, the Date checks throw System.ArgumentException and System.ArgumentOutOfRangeException depending on which check you do). As a programmer I'd have to remember to add a catch for the right Exception type in the right place for those specific types of exceptions (ie, not every place uses a generic "catch (Exception e)"). My comment is that it's really easy to add checks because it's really convenient, but then we are also silently adding other exception types that can be thrown without noticing and potentially breaking our code. I'm interested in seeing how you approach this issue in general because this type of thing happens fairly regularly in everyday coding and I don't have a good answer because the alternative is to write more code, which sort of defeats the purpose...
Good question. I would say that if you are struggling with which checks return which exceptions, you could add a code comment at that spot identifying which exception would be returned. However, the bigger solution is to document your method using XML code comments, including which exceptions are returned so that the caller will know what to look for.
Hmm, this specific case is quite a traditional way of programming (checking build-in type values at method level). I think Age should be a separate type, where these checks are done during construction. One could even argue that the internal datatype could be something else than int (TimeSpan?). But that's not important when using it, as you'd have abstracted it away.
Thanks for the video! I understand that this example was used just for demonstration, but I am still curious. Would not it be better to define a ValueObject for age and do all basic validation there rather than in all different methods that use age as int?
It would depend on how many separate places work with an age value separately. For instance, once you validate age, you don't need to continue validating it if the methods are private. It is only in your public endpoints that you need to validate the age value.
we need an advanced NET, C#, SQL Server real world project similar to the alread 3 projects on the channel but for more advanced Devs so they can gain even more experience and skills
what is helper method? defense in depth slow blob explanation. Can be trimmed to 15min easily. Di is about setting boundaries. How the data should look like?
If I use this on a web application, is there a way to deliver the Throw message as a toast notification, or into a Label instead of Console.WriteLine()?
I haven't watched the entire video, but use fluent validation for user input, EG: form submissions. Use Guard Clauses for library methods, to ensure values are within constraints. EG: Making sure an index is >= 0
Fluent Validation is just another way of approaching this problem. It is designed more for the immediate input rather than validation throughout, though.
They have their place as well. Sometimes you need to do validation inside of your application (defense in depth), where annotations might not work well. Also, annotations don't handle every scenario. For instance, if you are asking for just a small piece of data, it might not make sense to make a model out of it and add annotations.
yep, there is. It's called FluentValidation. I've been using it for a long time and this video got be thinking because I thought that throwing exceptions like this is a bad practice.
Yep, there is. The problem with always doing that (sometimes it is appropriate) is that you are relying on the caller to know about the return types that mean the operation did not succeed. For instance, say your method sends emails. If you send in bad data (say an email address with no @ symbol), the method could either throw an exception or it could return a status of "bad data". If it returns that status, technically the method completed successfully (it did not crash). If the caller (who you might not control) does not realize that a bad status is possible, they could ignore the return information and continue on, assuming the email had been sent. If the method throws an exception, it will force the user to deal with the issue or it will crash their application. Either way, they cannot continue in a bad state. That's why exceptions exist. That's why just about every .NET library provided by Microsoft will tell you which exceptions it will throw.
@@IAmTimCorey Thank you, Tim. I am a big fan of your work. And yes I agree, in many situations such as when you do not control the caller throwing an exception is better. And I guess I wish some of the Go and Java exception related features were in C#. Status object is also sometimes useful when it is expected that error will occur such as when UI is validated.
I’ve been using the Dawn.Guard package for this for years. Very similar. Throw looks newer but Dawn.Guard has been around for ages and has a cool name 😎
Not-assertions. I realky wish C# just had requires and ensures clauses. Do we wanr to express requirements in terms of counter-examples? Kind of like uint instead of sint (should be nat, int anyway).
@@IAmTimCorey instead of “arg.Throw().IfNegative();” perhaps just: C# syntax a la “requires arg >= 0;” (Design by Contract as in some C# variants - and in the old CodeContracts library from MSR).
I always thought exceptions are something truly exceptional. Bad data is something you should expect and not something to throw an exception for. You validate rules up front and return a list of broken rules. Otherwise, you might end up with tons of 1 off errors where the user has to keep trying. Plus, exception stack traces make it heavy.
These things are exceptional. Bad data is not something you should allow. Just returning a list of broken rules doesn't always work. For instance, if you are writing a NuGet package, just returning a set of broken rules forces the caller to handle rules, to validate if the rules have been passed or not, and what to do if they have not passed. The risk to your caller is pretty high. The fact is that the bad data should not have been sent in the first place, so there is already a violation of the desired inputs. Expecting a caller to violate the expected inputs but to handle the failed rules properly is an assumption. You never want your application to continue working in a bad state. That can lead to unexpected behaviors. For instance, what if your library sent emails to customers saying that their order was shipped. Now imagine if the caller of your library sent you an invalid email address. If you just have rules saying that it was an invalid email address, technically the method will return with success. Meaning, it will run. If the caller does not catch the fact that there were errors and the method didn't actually send an email, it might proceed with the assumption that the email was sent. Then, it marks that the email was sent in the database. Now you have a record in your database that you sent an email when you never sent the email. That is why exceptions exist. We stop everything and say "this is not ok". The method does not return successfully. You can still catch the exception, identify the problem, and continue, but now you know for sure that the method failed to work. Now you will not update the database to reflect that an email was sent.
@@IAmTimCorey There is a difference between a nuget library and your own project. I would agree that if you are a 3rd party library, you need to throw exceptions as what you describe would be a problem. However, if it is your own project, you should be validating your own input up front and not throw an exception because of some required field is missing. You should be able to check for those things up front and return with broken rules so when an exception does happen, it should truly break the flow. However, this is more of a religious debate with different camps so it would probably be too much to discuss here. :)
@@MetalKid007 @IAmTimCorey I think there is a missed paradigm here. It seems MetalKid007 is thinking lets catch all the issues and tell the user about them all asap instead of stopping the program for each issue. Maybe it's an import of a csv file with addresses. Do we really want to throw an exception for each address that isn't right that be a pain for the user. Line 8 is missing a state, user fixes and reimports, issue with address1 on line 10 and so on. Instead you'd like to have a list of data issues for the user to fix to shrink the import into two attempts. This would be a part of the process. Click import, Validate all inputs and if everything is valid then import the data. However, Tim Corey's example is more in the business layer of the application where you should be expecting all of your data already to be valid and legit and this is more of guarding your business logic from having bad data. I think you're both right. On the front end validate and tell the user as much as possible so they can get it all fixed at once but once you're in the business layer then throw exceptions to prevent bad data in the database or reports or such.
@@dreddy5187 Ultimately, yes, that is what I was saying. However, here is the thing. If you validate the rules up front, why would you need to add extra exception handling here as it was already validated? You'd be essentially running the same checks again. For me, I try to return IResult types back where the code above can handle all the situations automatically so the code you write handles these broken rules being returned automatically. You'd only throw an exception if you have no way of knowing if those rules were validated before - essentially, if you were writing your own 3rd party library that others would use as you can't guarantee callers would look at your result and handle the problem correctly. That is why, I would say @IAmTimCorey is correct about exceptions when it comes to 3rd party libraries, but you shouldn't need to do that for your own logic if you can run the rules and handle them up front yourself. :)
@@MetalKid007 I'd agree if I was the only one to ever touch the code or use the method and had tests for every way it gets used to verify there is no issue. Defensive programming is programming you never want to trigger but when it does you're always very thankful. I could be working on a project that you started at a previous company and change how the import works or maybe I'm updating the front end from win forms to mvc and I miss a piece of your validation. I'd be happy to see that your business logic catches bad data and throws exceptions when that occurs instead of making a false assumption that all values coming into the method is valid. It's almost as if you're decoupling the data a bit more. If I were to give you some data in an excel sheet for a report you have to give a manager would you assume everything is right or would you double check things and kick it back to me when things are bad? Hopefully the double check is quick and nothing is found but once you find an issue it'd be worth it's time in gold instead of sending a bad report to your manager.
The bigger problem is that AgeInDecades accepts signed integers. Switching to unsigned integers would better represent human ages. As for the upper limit, that is difficult to determine. I fear setting it to 130 will require additional updates not so long in the future. Another solution is to create a new type Age and guard against bad data internally. By the way, I prefer the long form guard clause over options shown here. I don't see any real benefits that warrant adding an additional dependency. With the Throw package, are the strings localized for major world languages? My customers complain extremely loudly when they get a message in English.
That would seem logical, but it's in fact a pitfall. In many cases data is stored as a signed int, because it's the default data type. And people would make the mistake of simply casting to unsigned in order to use this function. However, casting a negative int to an unsigned int is legal(!) and will not throw. It will lead to a very large value. This has actually been the cause of many bugs in production in the C area.
I like the concept but IMO throwing exceptions creates leaky abstractions, incurs performance costs and doesn't feel "Exceptional" when validating data. This feels more like you have detected an error and as such you could return an error, maybe even just returning the exception instead of throwing it using something like the Result type. This is much better for performance and allows the application to handle errors gracefully leaving exception handlers for when something is truly exceptional/unexpected
It sounds like you are thinking of this only for validation at the edge. This is more for validation internally (defense in depth). For instance, a class library that is a NuGet package does not have access to the user and does not have the ability to verify things have been done right. So, it should throw exceptions when things are not as expected/needed. Otherwise, you will allow an application to continue on in an invalid state. For instance, if the NuGet package returned a result type that said error, that would require the caller to properly identify that the result type means failure since the method called technically succeeded. Assuming a return type will be handled is not something I am comfortable with doing. Imagine if the method was to send an email to a customer letting them know that their order had been placed (the receipt email). Now imagine you sent an invalid email address in (it was missing the @ symbol). In your system, the method would complete and it would return information. The return type would say "that didn't work". The caller, however, could just fire off the method call and continue, assuming that it worked. They could then mark the email as sent in the database. Now there is a record that the email was sent, but it wasn't. If, instead, you threw an exception, the caller would have no choice but to acknowledge the error and deal with it. "Worst" case, the application would crash. That would mean that the record would not be marked in the database as sent. So even in the worst case, the application would not continue running so it would not put bad data into the system. Best case, the user handles it and acknowledges that there is an issue and deals with it. Either way, the data is safe. This is why we have exceptions. This is why almost every NuGet package or library from Microsoft lists the exceptions that will be thrown when you try to use it improperly. Overuse of exceptions can be a bad thing, but I see too many people leaning towards underuse. That's even worse. Applications that run in a compromised state lead to bad data and possible exploitation.
@@IAmTimCorey Hi Tim, thanks for your response. I think the way i worded my comment made it seem like i want to abolish all exceptions. This is far from what i actually think! I agree with you in part on your response. You can still achieve application integrity without throwing exceptions for most operations. In your example, the send email method could return a result object, something similar to Result object from Language-Ext. A Result object has two states, it's either faulted or succeeded. Handling either of these states would be done via .Match(sucess => { do something on success }, error => { do something on error }). In this scenario the application wouldn't end up in a invalid state as the success logic only gets called if everything ran smoothly. It is also alot more explicit about the potential errors of calling this method from just looking at the method signature. You still may want to throw an exception if the send mail function can't establish a connection with the mail server, or if you are validating data in a constructor and its too late to return a error to the client. Throwing an exception means you either catch and handle that exception at the point of use, in which case why not just return a error, its much more performant and IMO easier to read. Alternatively you might use a catch-all exception handler, which could return a generic error to the client. If the catch-all is turning specific exceptions from deep within the application into useful error messages then you might have a leaky abstraction.
My goal wasn't to just show you a cool NuGet package. My goal was to teach you what the guard clause is, why we need it, and how to implement it. That's why I didn't just say "here is how to use this package". My goal is always to teach you how to work in the real world. Real-world development is not really about knowing what tools are available (that is helpful, but not the main thing). Instead, it is about knowing how and when to use certain logic to build things. When I taught an intro to C# course at a local college, my students would know about 90% of all of the syntax they needed by week 5, yet the course was 16 weeks long. The reason they knew all of the syntax by week 5 was because that's the least important part of programming. The most important part is knowing how to put it all together, knowing what pitfalls to avoid, and knowing how to make the best choice for their specific circumstances. Just knowing trivia won't get you far. Knowing when to use it will make a HUGE difference. That's why I teach the way I do. I hope that helps. I'm glad you enjoyed learning about Throw.
@@IAmTimCorey Sorry be so terse earlier. The video title is pretty clear. Suggestion: add some time-stamps for the different sections of the lesson. I think that would help people find the bits they are interested in.
Right now, I don't have the time necessary to add timestamps to my videos. It adds a LOT of overhead to uploading a video. That means I would produce fewer videos. Whenever possible, I focus on more content. However, I do open it up to the community. If anyone watches a video of mine and decides to record key moments, they can post them in the comments. I'll take those timestamps and put them in the description so that everyone gets the chapters. If you browse through my content, you will notice that this happens a LOT, which I greatly appreciate.
This would be a cool project to create. But for me, unless I found myself writing a large amount of guard clauses frequently, I'd rather put the effort into learning something more useful to me and just write a few if statements. In my experience most guard code is simple enough to not warrant something like this.
Sorry guys, could someone redirect me on videos about how to deal with security? Like how to hide access to sql and how to hide sensible data on the app itself? I'm having trouble finding them and i REALLY need to study it....
It depends on what you mean. If you are talking about hiding the connection string to SQL and hiding other sensitive data like password, you would do that using appsettings.json, secrets.json, and potentially Key Vault. I cover how to do this safely in my .NET Core AppSettings In Depth course ( www.iamtimcorey.com/p/net-core-appsettings-in-depth ). We see how to ensure that our connection strings are not saved in source control, are not visible to outsiders, and yet are accessible when needed. By the way, I'm using "connection string" to mean any sensitive data like that. The basics are as follows: put your local connection string info into secrets.json. That will keep it on your computer only and will make sure they don't go into source control. Then, use the build process to inject the correct connection string into your appsettings.json file during build. Or, if you are using a cloud provider like Azure, you can either use Azure Key Vault to store all of your connection strings for all environments or if you deploy your website to an Azure Web App, you can use the secure connection strings section in the portal to store your connection strings. It will override your appsettings.json file as needed. If you meant "how do I hide direct access to SQL, etc." then the answer is through an API. Create an API and then you control everything through it. That almost totally eliminates potential SQL injection attempts, it ensures that users get the data in a specific way, and it allows for secure access even from desktop and mobile clients. I demonstrate this in my TimCo Retail Manager series among other places.
Your problem in this video is primitive obsession. The method signature accepts any int, which isn't true nor is it descriptive to the client. In my opinion, it's better to have an "always valid" approach rather than bubbling up exceptions for validation. However, the library is nice...
I think you are thinking only of the edge (users giving us data directly). I am talking about defense in depth. You shouldn't hit these throws because you should be giving correct data internally, but that's not always the case.
@@IAmTimCorey - I meant that deep in the domain, instead of this method accepting an int, it should accept an Age value object. For this object to be instantiated at the boundary of the system, it would need to conform to the validation rules. But passing around the Age object within your domain would ensure that all method signatures are honest and always valid. However, I can definitely see cases where you do need to through exceptions (such as if invariant rules are broken), and for this reason the package will be useful for this.
Maybe it's worth making a comparison to Ardalis.GuardClauses? I personally like the way of writing more with that library but I'm pretty sure it does the same thing.
As a very objective viewer I think this package is incredible 🤙🏼 (disclaimer, I’m the creator of the package)
Thanks Tim for your support and kind words, it means a lot ❤️
I was happy to feature it. It is a great package. I appreciate what you do for the community.
Good work sir.
Great work man, Appreciate the effort, one question please if i may,
is there a way to localize the exception message throwen?,
if not .. does the throwed exceptions have a unique underline number(similer to SQL Server error messages numberd) so i can localize it, thank you in advance.
will going to use it in my current project .. ❤️
Thanks! I appreciate what you do … not just on *this* video.
Thank you!
Also, in the Microsoft Community Toolkit NuGet Package there is a Guard Class that does something similar to the Throw Library but with fewer options
Yep.
GREAT VIDEO Tim as always😀
Thank you!
This is exactly the type of content I subscribed for, good stuff
Thanks!
next level. multiple options are in there.
Thanks!
A question about code quality and maintainability: in the default use case like "name.Throw()..." it uses System.ArgumentException by default. For long term readability and maintainability, would you code so that you specify the exception always, even though redundant in the current state of the project (eg, use "name.Throw(paramName => throw new System.ArgumentException($"Param name: {paramName}."))")?
The question comes from it not being clear which exception will be thrown just from reading the code. I had to look at the docs in order to know what the default exception type was.
Also, some checks throw different exceptions based on the type of check you are doing (eg, the Date checks throw System.ArgumentException and System.ArgumentOutOfRangeException depending on which check you do). As a programmer I'd have to remember to add a catch for the right Exception type in the right place for those specific types of exceptions (ie, not every place uses a generic "catch (Exception e)"). My comment is that it's really easy to add checks because it's really convenient, but then we are also silently adding other exception types that can be thrown without noticing and potentially breaking our code.
I'm interested in seeing how you approach this issue in general because this type of thing happens fairly regularly in everyday coding and I don't have a good answer because the alternative is to write more code, which sort of defeats the purpose...
Good question. I would say that if you are struggling with which checks return which exceptions, you could add a code comment at that spot identifying which exception would be returned. However, the bigger solution is to document your method using XML code comments, including which exceptions are returned so that the caller will know what to look for.
Really nice package! Thanks for the video on it.
You are welcome.
Absolutely love your videos, find myself binging your content for hours! 👌
Glad you like them!
Hmm, this specific case is quite a traditional way of programming (checking build-in type values at method level). I think Age should be a separate type, where these checks are done during construction. One could even argue that the internal datatype could be something else than int (TimeSpan?). But that's not important when using it, as you'd have abstracted it away.
Thanks for the video! I understand that this example was used just for demonstration, but I am still curious. Would not it be better to define a ValueObject for age and do all basic validation there rather than in all different methods that use age as int?
It would depend on how many separate places work with an age value separately. For instance, once you validate age, you don't need to continue validating it if the methods are private. It is only in your public endpoints that you need to validate the age value.
Excellent tool, very Exceptional in handling validations and exceptions. I Love it
Thank you Tim, as always your the best.
You are welcome.
The desire for this feature goes back to the proposed Code Contracts from over a decade ago.
The nice thing here is that it is simpler and more flexible.
Super helpful, thanks for posting!
You are welcome.
Better than fluent validators.. Good to know throw package exist.. Thanks for the informative video.
You are welcome.
Good stuff Tim 👏
Thanks!
is there a good way to use the NuGet package for real-time validation during data entry? could you use in this in a filter method perhaps?
Mulțumim!
Thank you!
we need an advanced NET, C#, SQL Server real world project similar to the alread 3 projects on the channel but for more advanced Devs so they can gain even more experience and skills
I want to see some mongodb project with dot net.
Thanks for the suggestion. Please add it to the list on the suggestion site so others can vote on it as well: suggestions.iamtimcorey.com/
what is helper method?
defense in depth
slow blob explanation. Can be trimmed to 15min easily.
Di is about setting boundaries. How the data should look like?
I mean, how often do you add .editorconfig? It is a very good decision, if they happened to take it out of the (very busy) right-click menu
I add it to every "real" project I create.
an extra bonus of a throw helper function is that the JIT will not inline a function with a throw in it.
If I use this on a web application, is there a way to deliver the Throw message as a toast notification, or into a Label instead of Console.WriteLine()?
You would need to capture the exception at the UI layer and then trigger your message from there.
Wow!. ... Could have used that in the past.
Well, I'm glad you have it now.
Thanks Tim!
You are welcome.
I wish you said or put somewhere this was .net 6+ and wasn't available for previous .net core/framework. I need this for .net fw 4.8
I did say it in the video. Sorry you missed it.
Then look at the sources and write your own!
@@IAmTimCorey No I didn't miss it, it was just quite a bit into the video, mb I meant say it at the start or in the description 👍
Good work !
Thanks!
Nice, but how does this relate to fluent validation you have shown some time ago? Any reason to prefer one of them?
I haven't watched the entire video, but use fluent validation for user input, EG: form submissions. Use Guard Clauses for library methods, to ensure values are within constraints. EG: Making sure an index is >= 0
Fluent Validation is just another way of approaching this problem. It is designed more for the immediate input rather than validation throughout, though.
This looks more flexible but what about model data annotations?
They have their place as well. Sometimes you need to do validation inside of your application (defense in depth), where annotations might not work well. Also, annotations don't handle every scenario. For instance, if you are asking for just a small piece of data, it might not make sense to make a model out of it and add annotations.
I wonder if there is a package that would return a status object instead of throwing an exception
yep, there is. It's called FluentValidation. I've been using it for a long time and this video got be thinking because I thought that throwing exceptions like this is a bad practice.
Yep, there is. The problem with always doing that (sometimes it is appropriate) is that you are relying on the caller to know about the return types that mean the operation did not succeed. For instance, say your method sends emails. If you send in bad data (say an email address with no @ symbol), the method could either throw an exception or it could return a status of "bad data". If it returns that status, technically the method completed successfully (it did not crash). If the caller (who you might not control) does not realize that a bad status is possible, they could ignore the return information and continue on, assuming the email had been sent. If the method throws an exception, it will force the user to deal with the issue or it will crash their application. Either way, they cannot continue in a bad state. That's why exceptions exist. That's why just about every .NET library provided by Microsoft will tell you which exceptions it will throw.
@@IAmTimCorey Thank you, Tim. I am a big fan of your work. And yes I agree, in many situations such as when you do not control the caller throwing an exception is better. And I guess I wish some of the Go and Java exception related features were in C#. Status object is also sometimes useful when it is expected that error will occur such as when UI is validated.
I’ve been using the Dawn.Guard package for this for years. Very similar. Throw looks newer but Dawn.Guard has been around for ages and has a cool name 😎
Thanks for sharing.
How do you Compare this to .Net Contracts??
This is simpler and more flexible than Code Contracts.
Not-assertions. I realky wish C# just had requires and ensures clauses. Do we wanr to express requirements in terms of counter-examples? Kind of like uint instead of sint (should be nat, int anyway).
I'm not sure what you are asking for here.
@@IAmTimCorey instead of “arg.Throw().IfNegative();” perhaps just: C# syntax a la “requires arg >= 0;” (Design by Contract as in some C# variants - and in the old CodeContracts library from MSR).
I always thought exceptions are something truly exceptional. Bad data is something you should expect and not something to throw an exception for. You validate rules up front and return a list of broken rules. Otherwise, you might end up with tons of 1 off errors where the user has to keep trying. Plus, exception stack traces make it heavy.
These things are exceptional. Bad data is not something you should allow. Just returning a list of broken rules doesn't always work. For instance, if you are writing a NuGet package, just returning a set of broken rules forces the caller to handle rules, to validate if the rules have been passed or not, and what to do if they have not passed. The risk to your caller is pretty high. The fact is that the bad data should not have been sent in the first place, so there is already a violation of the desired inputs. Expecting a caller to violate the expected inputs but to handle the failed rules properly is an assumption. You never want your application to continue working in a bad state. That can lead to unexpected behaviors. For instance, what if your library sent emails to customers saying that their order was shipped. Now imagine if the caller of your library sent you an invalid email address. If you just have rules saying that it was an invalid email address, technically the method will return with success. Meaning, it will run. If the caller does not catch the fact that there were errors and the method didn't actually send an email, it might proceed with the assumption that the email was sent. Then, it marks that the email was sent in the database. Now you have a record in your database that you sent an email when you never sent the email. That is why exceptions exist. We stop everything and say "this is not ok". The method does not return successfully. You can still catch the exception, identify the problem, and continue, but now you know for sure that the method failed to work. Now you will not update the database to reflect that an email was sent.
@@IAmTimCorey There is a difference between a nuget library and your own project. I would agree that if you are a 3rd party library, you need to throw exceptions as what you describe would be a problem. However, if it is your own project, you should be validating your own input up front and not throw an exception because of some required field is missing. You should be able to check for those things up front and return with broken rules so when an exception does happen, it should truly break the flow. However, this is more of a religious debate with different camps so it would probably be too much to discuss here. :)
@@MetalKid007 @IAmTimCorey I think there is a missed paradigm here. It seems MetalKid007 is thinking lets catch all the issues and tell the user about them all asap instead of stopping the program for each issue. Maybe it's an import of a csv file with addresses. Do we really want to throw an exception for each address that isn't right that be a pain for the user. Line 8 is missing a state, user fixes and reimports, issue with address1 on line 10 and so on. Instead you'd like to have a list of data issues for the user to fix to shrink the import into two attempts. This would be a part of the process. Click import, Validate all inputs and if everything is valid then import the data. However, Tim Corey's example is more in the business layer of the application where you should be expecting all of your data already to be valid and legit and this is more of guarding your business logic from having bad data. I think you're both right. On the front end validate and tell the user as much as possible so they can get it all fixed at once but once you're in the business layer then throw exceptions to prevent bad data in the database or reports or such.
@@dreddy5187 Ultimately, yes, that is what I was saying. However, here is the thing. If you validate the rules up front, why would you need to add extra exception handling here as it was already validated? You'd be essentially running the same checks again. For me, I try to return IResult types back where the code above can handle all the situations automatically so the code you write handles these broken rules being returned automatically. You'd only throw an exception if you have no way of knowing if those rules were validated before - essentially, if you were writing your own 3rd party library that others would use as you can't guarantee callers would look at your result and handle the problem correctly. That is why, I would say @IAmTimCorey is correct about exceptions when it comes to 3rd party libraries, but you shouldn't need to do that for your own logic if you can run the rules and handle them up front yourself. :)
@@MetalKid007 I'd agree if I was the only one to ever touch the code or use the method and had tests for every way it gets used to verify there is no issue. Defensive programming is programming you never want to trigger but when it does you're always very thankful. I could be working on a project that you started at a previous company and change how the import works or maybe I'm updating the front end from win forms to mvc and I miss a piece of your validation. I'd be happy to see that your business logic catches bad data and throws exceptions when that occurs instead of making a false assumption that all values coming into the method is valid. It's almost as if you're decoupling the data a bit more. If I were to give you some data in an excel sheet for a report you have to give a manager would you assume everything is right or would you double check things and kick it back to me when things are bad? Hopefully the double check is quick and nothing is found but once you find an issue it'd be worth it's time in gold instead of sending a bad report to your manager.
The bigger problem is that AgeInDecades accepts signed integers. Switching to unsigned integers would better represent human ages. As for the upper limit, that is difficult to determine. I fear setting it to 130 will require additional updates not so long in the future. Another solution is to create a new type Age and guard against bad data internally.
By the way, I prefer the long form guard clause over options shown here. I don't see any real benefits that warrant adding an additional dependency.
With the Throw package, are the strings localized for major world languages? My customers complain extremely loudly when they get a message in English.
I think you missed the part where I said that the age check was just an example.
That would seem logical, but it's in fact a pitfall. In many cases data is stored as a signed int, because it's the default data type. And people would make the mistake of simply casting to unsigned in order to use this function. However, casting a negative int to an unsigned int is legal(!) and will not throw. It will lead to a very large value. This has actually been the cause of many bugs in production in the C area.
reminds me of fluent assertions
Yep, just another way of doing things.
Crazy useful
Thanks!
I like the concept but IMO throwing exceptions creates leaky abstractions, incurs performance costs and doesn't feel "Exceptional" when validating data. This feels more like you have detected an error and as such you could return an error, maybe even just returning the exception instead of throwing it using something like the Result type. This is much better for performance and allows the application to handle errors gracefully leaving exception handlers for when something is truly exceptional/unexpected
It sounds like you are thinking of this only for validation at the edge. This is more for validation internally (defense in depth). For instance, a class library that is a NuGet package does not have access to the user and does not have the ability to verify things have been done right. So, it should throw exceptions when things are not as expected/needed. Otherwise, you will allow an application to continue on in an invalid state. For instance, if the NuGet package returned a result type that said error, that would require the caller to properly identify that the result type means failure since the method called technically succeeded. Assuming a return type will be handled is not something I am comfortable with doing. Imagine if the method was to send an email to a customer letting them know that their order had been placed (the receipt email). Now imagine you sent an invalid email address in (it was missing the @ symbol). In your system, the method would complete and it would return information. The return type would say "that didn't work". The caller, however, could just fire off the method call and continue, assuming that it worked. They could then mark the email as sent in the database. Now there is a record that the email was sent, but it wasn't. If, instead, you threw an exception, the caller would have no choice but to acknowledge the error and deal with it. "Worst" case, the application would crash. That would mean that the record would not be marked in the database as sent. So even in the worst case, the application would not continue running so it would not put bad data into the system. Best case, the user handles it and acknowledges that there is an issue and deals with it. Either way, the data is safe. This is why we have exceptions. This is why almost every NuGet package or library from Microsoft lists the exceptions that will be thrown when you try to use it improperly.
Overuse of exceptions can be a bad thing, but I see too many people leaning towards underuse. That's even worse. Applications that run in a compromised state lead to bad data and possible exploitation.
@@IAmTimCorey Hi Tim, thanks for your response. I think the way i worded my comment made it seem like i want to abolish all exceptions. This is far from what i actually think!
I agree with you in part on your response. You can still achieve application integrity without throwing exceptions for most operations. In your example, the send email method could return a result object, something similar to Result object from Language-Ext. A Result object has two states, it's either faulted or succeeded. Handling either of these states would be done via .Match(sucess => { do something on success }, error => { do something on error }). In this scenario the application wouldn't end up in a invalid state as the success logic only gets called if everything ran smoothly. It is also alot more explicit about the potential errors of calling this method from just looking at the method signature.
You still may want to throw an exception if the send mail function can't establish a connection with the mail server, or if you are validating data in a constructor and its too late to return a error to the client. Throwing an exception means you either catch and handle that exception at the point of use, in which case why not just return a error, its much more performant and IMO easier to read. Alternatively you might use a catch-all exception handler, which could return a generic error to the client. If the catch-all is turning specific exceptions from deep within the application into useful error messages then you might have a leaky abstraction.
defense in depth : aka also not taking the approach "assuming i never have a code bug"...
Yep.
I think Ezekiel is over 2600 years old. But he probably won’t be using the app.
I am Tim Corey
Interesting. I could have sworn I was sitting right here.
LOL, I was expecting the reply to be "ArgumentException: Sorry, you can't use my name.". Need to write some unit tests to prevent a regression.
Great package. Thanks!
18 min. of intro/exposition is a bit much...
My goal wasn't to just show you a cool NuGet package. My goal was to teach you what the guard clause is, why we need it, and how to implement it. That's why I didn't just say "here is how to use this package". My goal is always to teach you how to work in the real world. Real-world development is not really about knowing what tools are available (that is helpful, but not the main thing). Instead, it is about knowing how and when to use certain logic to build things. When I taught an intro to C# course at a local college, my students would know about 90% of all of the syntax they needed by week 5, yet the course was 16 weeks long. The reason they knew all of the syntax by week 5 was because that's the least important part of programming. The most important part is knowing how to put it all together, knowing what pitfalls to avoid, and knowing how to make the best choice for their specific circumstances. Just knowing trivia won't get you far. Knowing when to use it will make a HUGE difference. That's why I teach the way I do. I hope that helps. I'm glad you enjoyed learning about Throw.
@@IAmTimCorey Sorry be so terse earlier. The video title is pretty clear.
Suggestion: add some time-stamps for the different sections of the lesson. I think that would help people find the bits they are interested in.
Right now, I don't have the time necessary to add timestamps to my videos. It adds a LOT of overhead to uploading a video. That means I would produce fewer videos. Whenever possible, I focus on more content. However, I do open it up to the community. If anyone watches a video of mine and decides to record key moments, they can post them in the comments. I'll take those timestamps and put them in the description so that everyone gets the chapters. If you browse through my content, you will notice that this happens a LOT, which I greatly appreciate.
This would be a cool project to create. But for me, unless I found myself writing a large amount of guard clauses frequently, I'd rather put the effort into learning something more useful to me and just write a few if statements. In my experience most guard code is simple enough to not warrant something like this.
That's fine. That's why we have options.
Sorry guys, could someone redirect me on videos about how to deal with security?
Like how to hide access to sql and how to hide sensible data on the app itself?
I'm having trouble finding them and i REALLY need to study it....
It depends on what you mean. If you are talking about hiding the connection string to SQL and hiding other sensitive data like password, you would do that using appsettings.json, secrets.json, and potentially Key Vault. I cover how to do this safely in my .NET Core AppSettings In Depth course ( www.iamtimcorey.com/p/net-core-appsettings-in-depth ). We see how to ensure that our connection strings are not saved in source control, are not visible to outsiders, and yet are accessible when needed. By the way, I'm using "connection string" to mean any sensitive data like that.
The basics are as follows: put your local connection string info into secrets.json. That will keep it on your computer only and will make sure they don't go into source control. Then, use the build process to inject the correct connection string into your appsettings.json file during build. Or, if you are using a cloud provider like Azure, you can either use Azure Key Vault to store all of your connection strings for all environments or if you deploy your website to an Azure Web App, you can use the secure connection strings section in the portal to store your connection strings. It will override your appsettings.json file as needed.
If you meant "how do I hide direct access to SQL, etc." then the answer is through an API. Create an API and then you control everything through it. That almost totally eliminates potential SQL injection attempts, it ensures that users get the data in a specific way, and it allows for secure access even from desktop and mobile clients. I demonstrate this in my TimCo Retail Manager series among other places.
@@IAmTimCorey Thank you so much, now i know where to look and what to type for info gathering 🙏♥️🙏
Your problem in this video is primitive obsession. The method signature accepts any int, which isn't true nor is it descriptive to the client. In my opinion, it's better to have an "always valid" approach rather than bubbling up exceptions for validation. However, the library is nice...
I think you are thinking only of the edge (users giving us data directly). I am talking about defense in depth. You shouldn't hit these throws because you should be giving correct data internally, but that's not always the case.
@@IAmTimCorey - I meant that deep in the domain, instead of this method accepting an int, it should accept an Age value object. For this object to be instantiated at the boundary of the system, it would need to conform to the validation rules. But passing around the Age object within your domain would ensure that all method signatures are honest and always valid.
However, I can definitely see cases where you do need to through exceptions (such as if invariant rules are broken), and for this reason the package will be useful for this.
Thank you Tim, I love this video and I will certainly use Throw() in my application.
You are welcome.
Maybe it's worth making a comparison to Ardalis.GuardClauses?
I personally like the way of writing more with that library but I'm pretty sure it does the same thing.
Thanks for the suggestion.