--- tags: Pluralsight Note, Defensive coding in C# --- # Defensive Coding In C# ##### What We Should Defend From ? ![WhatWeDefend](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/WhatWeDefend.png?raw=true) ## Define Defensive Coding > Defensive coding is an approach to improve software and source code, in terms of: > - General quality - reducing the number of software bugs and problems > - Making the source code comprehensible - the source code should be readable and understandable, so it is approved in a code audit. > - Making the software behave in a predicatable manner despite unexpected inputs or user actions. #### How To Strengthening Our Defenses - Goal - Code Quality - Code Comprehension - Code Predictability - Validating method arguments - Handling nulls - Returning predictable results - Managing exceptions ### Goal - Code Quality - Defensive coding helps improve code quality primarily through automated code tests that exercise each logical unit of the application. - Unit testing helps us evaluate the quality of our defenses, and we can run the tests after each code change protecting the application by affirming its operations are not adversely impacted by the change - Code Comprehension - The easier our code is to read and understand, the easier it is to modify and maintain. - Code that is comprehensible has clear intent minimizing inadvertent or incorrect modifications - Better protecting our code from changing requirements and multiple developers over time - Code Predictability - Defensive coding helps improve code predictability through user entry validation clearly-defined method inputs and outputs, and exception management. so no matter what goes wrong, despite user errors and unforeseen circumstances, our application protects itself and continues on successfully ### Competing Goals ![CompetingGoals](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/CompetingGoals.png?raw=true) - we should try to **get a balance** between no defensive coding and adding too much unnecessary protection without providing benefits - To define the correct amount of defensive code based on the purpose of a particular feature - Consider Risk vs Defenses - The greater the weight of the risk, the greater the defenses to mitigate this risk ![RiskVsDefenses](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/RiskVsDefenses.png?raw=true) ### Code Comprehension - Easy to read - Generally, code is easy to read is organized and well-formatted - code should has clear names and reasonable-szie classes and methods - Have a clear intent - Each piece of code should have one clear purpose. - The easier it is for other developers to understand what intended the code to do, the less chance for introducing bugs over time. - Simple - Complex code is difficult to maintain, which can lead to changes that cause hard-to-find bugs. - Thoughtful - Thoughtful seems like an odd characteristic of code. but by conscientiously considering each line of code we write, we make our code easier to read, easier to understand, and easier to change and maintain over time. #### Refacor > Refactoring is the process of restructuring code, altering its organization without changing its behavior. - Single Responsibility Principle - build our code as a set of single-focused methods each with a single responsibility. - that makes the code easier to manage and maintain, easier to reuser, and easier to test. - Since methods perform actions, the method name should be a verb with an optional subject that verb is acting on. - Separation Of Concerns - Separation Of Concerns involves separating an application into distinct parts where each part addresses a specific concern or aspect of the application - Dividing our application into layers allows us to focus the code in each layer to a specific purpose, clarifying our intent. - This is often done with domains or layers - **Presentation layer** for the user interface and visual appearance of the application - **Business logic or Services Layer** for the logic and calculations that perform the key operations of the application - **Data layer** for the collection of data and interface to the data stores. - Don't Repeat Yourself (DRY) - we should minimize repeated code - Repeating codes in multiple places means there are more code to maintain, more code to test, and future developers need to somehow know that any change to one needs to be repeated in all. - Reuse code and methods instead of repateing it by copying and pasting ### Code Quality - Code Reviews - Code Reviews involve one or more developers evaluating your code quality by examining your source code, though these tend to look more at conformance to standards than actual code quality. - Code Execution - Running the code confirms it executes appropriately and as specified by the requirements. - Unit Testing - Unit testing involves writing code that tests a unit often a single method of our code. - It automates the execution of the code to efficiently confirm a multitude of scenarios. - Unit testing provides a way to evaluate the state of our defenses - Unit Test Steps ![UnitTestingSteps](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/UnitTestingSteps.png?raw=true) - Guideline Of Define Test Case - Valid Inputs - Select a set of valid inputs. These should include commonly entered values. - Invalid inputs - Data Entry Rules - Identify the data entry and validation business rules - Edge cases - e.g. Is there a minimum or maximum value? - e,g. For string value, Is there a minimum or maximum length? - Possible exceptions - Define conditions that could generate exceptions, and assert it - Empty and null values ### Code Predictability > Code Predictability means that the application behaves as expected, that it follows the principle of least surprise. > The principle of least surprise suggests that each feature of our application "should behave in a way that most users will expect it to behave" Predictable code involves anticipating these scenarios and specifying how the code should react by performing some basic what-should-happen-if analysis early in your project. - Ask yourself "what should happen if..?" - The user enters invalid data ?! - e.g. user type in a word instead of a number - The user breaks a business rule ?! - e.g. user provide a data which is not in the required date range - An Operation succeeds, or fails !? - e.g. An order processing operation completes successfully - Do we provide information to the user or leave them wondering ? - Did the order go through ? - e.g. An order processing operation completed failed - what information does the user need to remedy the issue ? - Something goes wrong ? - How should the code react to the unexpected conditions or exceptions ? - you should have clear and standard guidance as you build your application and have a consistent approach to handling errors and displaying validation and error messages. --> e.g. 處理方式需使用相同的邏輯. - perform what-should-happen-if analysis as you build each feature to define the specific validation, business rules, and operations for that feature. This information is helpful when building the feature and writing its unit tests. --> 定義需求 - Building predictable code goes hand in hand with writing unit tests confirm the predicted behavior --> 透過單元測試驗證邏輯 ## Defense Our Method - Guard against invalid arguments - Return predictable results - Only throw expected exceptions #### Validating method arguments - Defining Clear Method Signatures - Surrounding Our Operations with Conditionals - Failing Fast with Guard Clauses - Unit Testing for Expected Exceptions - Refactoring Our Methods ### Defining Clear Method Signatures - Method Name - the method name should be a verb with an optional subject that verb is acting on. e.g. SendEmail - Method Parameters - Parameter Name - it should describe more clear the data passed into this method - Parameter Type - we should specify the parameter type that the method needs - Parameter Order 1. Start with the parameters that method is action on 2. Most important to lease important 3. Optional Parameters - Consider defining flags and configuration as optional parameters with a good default to make it even easier for other code to call this method - [Optional Parameters Reference](https://www.c-sharpcorner.com/UploadFile/mahesh/optional-parameters-in-C-Sharp/) ##### Call Method - Named Arguments - it is useful if you only want to change one of the flags without changing the others. - All they both are okay (Comprehension) , it is up to you that selecting which implementation. - ![NamedArgument](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/NamedArgument.png?raw=true) - ![NonNamedArgument](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/NonNamedArgument.png?raw=true) ### Surrounding Our Operations with Conditionals ![Surrounding](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/Surrounding.png?raw=true) - To Use conditionals protect against invalid arguments - It don't provide any meaningful detail information about validation issues to the calling code - Make the code a bit harder to read ### Failing Fast with Guard Clauses ##### Failing Fast > Failing Fast means that code checks early on if there are any issues and immediately fails instead of proceeding when it can't be successful ##### Guard Clauses Define > - Guard clauses are defined with a set of statements written at the top of the method that validation incoming parameters > - Guard Clauses only let valid arguments into our method, so our method operations only execute with valid inputs > - The purpose of a guard clause is to ensure that method the method receives valid and expected input. If not, The guard clause fails fast > - Guard Clauses failes fast by immediately returning or throwing an exception > ![guardClause](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/guardClause.png?raw=true) ##### The Benefits Of Guard Clauses - Guard Clauses define all of the argument preconditions up front. - This makes our method more informative because the exception defines what's wrong - This provides a clear implementation of the validation and business rules pertaining to the method's argument - Guard Clauses that throw exceptions provide a way to pass information about the validation error out to the calling code using the exception messages. The calling code can catch the error and react accordingly - Using Guard Clauses caused our methods to fail fast preventing invalid arguments from reaching our operations. - Guard Clauses can fail fast by returning early or throwing exceptions - Guard Clauses can provide details information about why argument was invalid. Using exception messages, and optionally, specifying which argument is invalid. ### Unit Testing for Expected Exceptions ![UnitTestForExpectedException](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/UnitTestForExpectedException.png?raw=true) ### Refactoring Our Methods ##### Separate Validation Logic From Our Method ![RefactorMethod](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/RefactorMethod.png?raw=true) - Why !? - Because SRP - How !? - Help method or set of help methods for validation - ![HelpMethod](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/HelpMethod.png?raw=true) ![RefatorMethodCalling](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/RefatorMethodCalling.png?raw=true) - Method Overloading - We can use method overloading and define one overload with our validation and one with our operation - Method Overloading involves using the same method name but different set of method parameters - ![OverloadingMethods](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/OverloadingMethods.png?raw=true) - It is a common skill to move validation logic by Method Overloading out. but You need to assume the private method won't throw exception in this example. - Build a guard class with a set of guard methods - Guard method has its own set of generalized validation methods. - Unlike help methods which focus on defining business rule for a specific argument, the guard class contains a set of more generalized methods thaat that can be reused for any validation in the application. They don't contain any argument specific code - ![GuardClass](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/GuardClass.png?raw=true) ![GuardClass2](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/GuardClass2.png?raw=true) - Steps - move the complexity of our argument conversion and validation to another method or a set of methods - Define a utility methods as static - Access static methods using the class name ## Handling nulls ##### Null > - The absence of value > - Not the same as zero > - Not the same as an empty string > - If we don't specify a value, a default value is assigned based on the property's type > - Value Type defaults to a specific based on their type e.g. boot type default to false > - Reference Type defaults to null ##### Why Use Null ? - Nulls are useful for knowing difference between not yet set and a value types default value - Nulls provide default value for reference types. Without Null, What we use as a default? ### Declaring Nullable Value Types ##### Nullable Value Types > ![NullValueType](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/NullValueType.png?raw=true) - Nullable value types variable default to null and we can assign a value or null #### Defending Our Code from Null Nullable Value Types ![DefendingNullValueType](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/DefendingNullValueType.png?raw=true) - As Needed, Use nullable value types to clearly distinguish the difference between a value type's default value and no value at all. - This is useful when tracking whether or not the user entered a value - Guard methods from a null using the HasValue property of the Nullable value type. - Get value using the Value property of Nullable - Currently, we could use pattern matching to check whether the variable is null instead of using of HasValue property and Value property. ```C# // example int? maybe = 12; // if maybe is null if ( maybe is null ){} //if maybe's HasValue is true and maybe's Value has value if ( maybe is int number){} ``` [Null 檢查的參考連結](https://learn.microsoft.com/zh-tw/dotnet/csharp/fundamentals/functional/pattern-matching#null-checks) ### Defending Our Code from Null Reference Types ![DefendReferenceType2](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/DefendReferenceType2.png?raw=true) ![DefendNullReferenceType](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/DefendNullReferenceType.png?raw=true) - Use **is null** to check a reference type(or nullable value type) for null - Using **is null** is a greate way to check a reference type for null ```C# // example int? maybe = 12; // if maybe is null if ( maybe is null ){} //if maybe's HasValue is true and maybe's Value has value if ( maybe is int number){} ``` [Null 檢查的參考連結](https://learn.microsoft.com/zh-tw/dotnet/csharp/fundamentals/functional/pattern-matching#null-checks) - Use the null conditional operation(?) to short circuit member navigation - the null conditional operation all us to check for null in a member navigation chain ```C# // example A?.B?.C(); ``` [Null-conditional operators 參考連結](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-) ### Reference Type Nullability Features ( this feature only works in C# 8 or higher ) ![NullabilityFeature](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/NullabilityFeature.png?raw=true) - The Nullability Features allow us to define specifically the types as non-nullable or nullable - The Nullability Features allow us to declare our intent more clearly to other developers, our future self, and the compiler - If the compiler know our intent, it can better warn us whether we write code that is inconsistent with the intent ![NullabilityFeatureExample](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/NullabilityFeatureExample.png?raw=true) - the declare of the parameter at method CalculateMargin is Non-Reference Type #### Non-Nullable Reference Type ![Non-Nullable-Reference-Type](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/Non-Nullable-Reference-Type.png?raw=true) When we enable the Reference Type Nullability Features - Reference type variable can not be null - We can't explicitly define the reference type variable is supposed to be null - Any reference type without a question mark(?) is assumed to be a Non-Nullable Reference Type - Must be initialized to a value - The compiler requires that each Non-Nullable Reference Type variable be initialized to a non-null value and never assigned to null - This ensures that variable is safe to use without first checking for null - The compiler verified - compiler enforces rules that support this intent #### Nullable Reference Type ![Nullable-Reference-Type](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/Nullable-Reference-Type.png?raw=true) When we enable the Reference Type Nullability Features - Reference type variable may be null - we indicate that reference type may be null the same way we indicate nullable value types with question mark - Default of null - the default of Nullable Reference Type is null - Compliler suggests check for a null reference - the Compliler suggests that we check for a null neference before using a variable - the variable can only be used safely when the compiler can guarantee that the value isn't null #### Nullable Context ![NullableContext](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/NullableContext.png?raw=true) #### Setting of Project File ![NullableContextSetting](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/NullableContextSetting.png?raw=true) #### Setting Value ![NullableContextSettingValue](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/NullableContextSettingValue.png?raw=true) #### Nullable Directive ![NullableDirective](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/NullableDirective.png?raw=true) ##### 參考資訊 [C# 8.0 and Nullable Reference Types](https://learn.microsoft.com/en-us/archive/msdn-magazine/2018/february/essential-net-csharp-8-0-and-nullable-reference-types#essential-net) [Embracing Non-Nullable Reference Types in C# 8](https://www.automatetheplanet.com/embracing-non-nullable-reference-types/) [解決可為 Null 的警告](https://learn.microsoft.com/zh-tw/dotnet/csharp/language-reference/compiler-messages/nullable-warnings) [可為 Null 的變數注釋 --> ! ](https://learn.microsoft.com/zh-tw/dotnet/csharp/nullable-references#nullable-variable-annotations) ```C# name!.Length; ``` [可為 Null 的參考型別](https://blogs.uuu.com.tw/Articles/post/2022/04/27/%E5%8F%AF%E7%82%BA-Null-%E7%9A%84%E5%8F%83%E8%80%83%E5%9E%8B%E5%88%A5.aspx) ## Returning predictable results 當 Guard Clauses 發現問題, 可以如何傳遞訊息給 Calling Code 呢 !? ### Defining Predictable Method Results !? ##### How Many Of Return Types ![WhatShouldOurMethodReturn](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/WhatShouldOurMethodReturn.png?raw=true) - Simple Value - Multiple Values - **Ref, Out, In** - **Tuples** - **Object or Objects** (將多個屬性放在自定義類別物件中) - Nullable Value - Nullable Reference - Void - Throw Exception ### Defining ref and out Parameters #### Ref Parameter ![RefParameter](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/RefParameter.png?raw=true) #### Our Parameter ![OurParameter](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/OurParameter.png?raw=true) ##### 參考資源 [C#雜記 — 參數修飾詞 in、out、ref](https://ad57475747.medium.com/c-%E9%9B%9C%E8%A8%98-%E5%8F%83%E6%95%B8%E4%BF%AE%E9%A3%BE%E8%A9%9E-in-out-ref-5e4d83816c3a) [in parameter modifier (C# Reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-parameter-modifier) [ref (C# Reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref) [out parameter modifier (C# Reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier) ### Returning a Tuple #### Tuple > A tuple is a data structure that has a specific number and sequence of elements. > Tuples are commonly used in four ways: > - To represent a single set of data. For example, a tuple can represent a database record, and its components can represent individual fields of the record. > - To provide easy access to, and manipulation of, a data set. > - To return multiple values from a method without using out parameters (in C#) or ByRef parameters (in Visual Basic). > - To pass multiple values to a method through a single parameter. For example, the Thread.Start(Object) method has a single parameter that lets you supply one value to the method that the thread executes at startup time. If you supply a Tuple<T1,T2,T3> object as the method argument, you can supply the thread's startup routine with three items of data. ```C# //Code Example var goods = (string goodsId, string goodsName, int goodsPrice, bool hasStock); ``` ![TupleExample](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/TupleExample.png?raw=true) - If you plan to use tupels, consider always defining named tuples to clairfy your intent - We can return multiple values from our method by return a tuple (we should define the structure of the tuple in the method signature as return type) - If you plan to use tuples, you don't need to pre-define this structure somewhere else in your application <-- Unlike class or structure - **If you don't want a standard consistent return type on all of our validation methods, you just need to return multiple values at some methods. you could use Tuple** ##### 參考資源 [Tuple Class](https://learn.microsoft.com/en-us/dotnet/api/system.tuple?view=net-6.0) [C# 7 新增的 Tuple 語法](https://www.huanlintalk.com/2017/04/c-7-tuple-syntax.html) [[筆記] C# Tuple與ValueTuple的差異](https://dotblogs.com.tw/noncoder/2019/09/28/tuple-new-old) ### Returning an Object - If you want a standard consistent return type on all of our validation methods, you could define your custom return type - this is a ultimate in providing a predicated result - Unlike Tuple, Using a custom class for our methods means that return structure is consistent and has identical property named everywhere it's used #### Define a Class - Define a class that specifies the structure of our desired standardized return type - ![DefineClass](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/DefineClass.png?raw=true) - It is important for the team to define how this class should be used. - for example : we could set as part of our team's coding standards that every validation method and save method will return this standard type ##### Use ![ObjectReturn](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/ObjectReturn.png?raw=true) ### Returning Predictable Results From Validation Methods ##### Sample Validation Method Implementation <--- How should it refactor !? ![StartRetrunValue](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/StartRetrunValue.png?raw=true) - Assume this implementation don't make sense for this type of method ##### Choose Return Type - ~~Nullable Value~~ - ~~Nullable Reference~~ - Null means a absence of value, it is not true neither false - the two Nullable Value/Reference does not seem useful in this case because the Validation method either passed or failed - ~~Void~~ - it should return value in this case. - ~~Throw Exception~~ ![ThrowExceptionAsReturnType](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/ThrowExceptionAsReturnType.png?raw=true) - We could throw exceptions, - but would another developer except our validation method throw exception ?! - but would we remember to catch exceptions when calling this method !? - Simple Value ![StartRetrunValue](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/StartRetrunValue.png?raw=true) - when calling a method that performs validation, it makes sense for it to return a Boolean value. - true if the validation is successful - false if the validation falsed. - Often we want to know more information, but Simple-Value can't achieve - When validating, we also want to know what was invalid and why so we can display an appropriate message to the user( providing detailed messages helps the user quickly remedy the issue.) - For example - Was the argument empty or null !? - Were the business rules broken !? - Ref / Out / Tuples ![TupleExample](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/TupleExample.png?raw=true) - we could use **ref** or **out** Parameters to return the validation message - we could define a tuple - but these are not consistent approach for all of our validation methods - Object ![ValidationObjectAsReturnType](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/ValidationObjectAsReturnType.png?raw=true) - we want to build a standard class for all of our validation methods - returning a custom class with the information which caller need - It is good predictable choose <-- By the teacher at pluralsight ### Returning Predictable Results From Simple Operations ![CalcuateMarginExample](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/CalcuateMarginExample.png?raw=true) - How we return validation information or let the calling code know there was an operation issues? ##### Choose Return Type - Simple Value & Throw Exception ![CalcuateMarginExample](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/CalcuateMarginExample.png?raw=true) - If Without locating and reading this code, will the developer calling this method know they should be catching these exceptions. - If you and your team standardize on a pattern of returning a value type and throwing exceptions, than the exception are expected and predictable, and this is a good choice - Object - we could define a specialized classes returning different results for our operation - Tuples & Nullable Value & Nullable Reference ![TupleNullableTypes](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/TupleNullableTypes.png?raw=true) - Nullable Type allow us to pass the result or null if the result can't be calculated. so we can clearly distinguish between not calculated and default value - the calling code won't be surprised by unexpected exception - If your method may be called from other code that would not expect an exception or if the application will have a long enhancement and maintenance life time, a more predictable tuple approach may be best ### Returning Predictable Results From Find and Retrieve Methods - Object & Throw Exception ![ObjectThrowExceptionAsRetrunType](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/ObjectThrowExceptionAsRetrunType.png?raw=true) - The calling code needs to know which exceptions to look for and catch any exceptions. - This is a common practice, if you and your team follow coding guidelines that standardize on throwing exceptions. - If you and your team have standardized on a thrown exception approach, return the item or throw an exception. - Nullable Reference ![NullableDiscountAsReturnType](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/NullableDiscountAsReturnType.png?raw=true) - Return result or null - If you don't need a message back, use a nullable reference type and return a null if result can't be get - Tuples & Nullable Reference ![TupleNullAbleReferenceAsReturnType](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/TupleNullAbleReferenceAsReturnType.png?raw=true) - This Approach can pass error message detailing the issue back to calling code. - Use the tuple technique if you need messages back from the method and want a clearly defined return type ### Returning Predictable Results From Complex Operations ![AssumeTheseCommontAsVeryManyThing](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/AssumeTheseCommontAsVeryManyThing.png?raw=true) ##### Choose Return Type - Simple Value ![AssumeTheseCommontAsVeryManyThing](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/AssumeTheseCommontAsVeryManyThing.png?raw=true) - we could return a simple value such as a Boolean identifying if the operation was successful or not. - If the return value is all the information that callind code needs, that's a clear and simple option. - Tuples ![TupleAsReturnOperation](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/TupleAsReturnOperation.png?raw=true) - we could return a success message for display to the user - Object ![StandardObjectAsReturnType](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/StandardObjectAsReturnType.png?raw=true) - we could create a custom class type. this would allow us to standardize the return type. - Void ![VoidOperation](https://github.com/s0920832252/C_Sharp/blob/master/Files/Defensive_Coding_In_CSharp/VoidOperation.png?raw=true) - we could return nothing and throwing exceptions to indicate any issues that arise ### Summary Which technique you decide to use for complex operations depends on the information you need from the method and on your coding guidelines. ##### Command-Query Separation Principle > Every method should either be **a command that performs an action**, or **a query that returns data to the caller**, but not both. ## Managing exceptions ##### Exception - Validation issues - Business Rule viloations - System Errors - Application failures ##### Exception Hansing - Process by which the application catches an exception - Respons to correct the problem or notify the user ### Exception Management Strategy - Shoud our methods theow exceptinos for validation or business rule violations? - If Yes - What type of exceptions ? - ArgumentException or ... ? - Custom Exception ? - If No , We want to use alternate techniques - Returning an object or a tuple that contains validation details - What about Ststem and Application Exceptions ? - How should we handle those ? - Should every routine be wrapped in an exception handler ? - Should you call a generalized exception handling method ? - Having a strategy for unexpected exceptions helps minimize the chances of an unhandled exception. - How Should the user be notified of exceptions ? - How and when Do we Log Exceptinos ? - For some errors, such as validation issues, you don't normally need logging, but for unexpected application or system exceptions, you may want to log the details. ### Net Exception - ArgumentException - InvalidOperationException ### Create Custom Exceptions ```C# [Serializable()] // <-- Optionally make the exception serializable public class DiscountNotFoundException : System.Exception { public DiscountNotFoundException() : base() { } public DiscountNotFoundException(string message) : base(message) { } public DiscountNotFoundException(string message, Exception inner) : base(message, inner) { } protected DiscountNotFoundException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) { } } ``` ##### 參考資源 [[C#] 序列化 (Serialization)](https://dotblogs.com.tw/atowngit/2009/12/16/12491) ## Summary * Improve code comprehension * Write code that is clean and easy to read. * Single responsibility principle * Separation of concerns * Don't repeat yourself(DRY) * Improve code quality * Build unit tests * Re-execute unit tests after each modification. * Improve code predictability * Principle of Least Surprise * Validate method arguments * Handle nulls * Return predictable results * Manage exceptions --- ###### Thank you! You can find me on - [GitHub](https://github.com/s0920832252) - [Facebook](https://www.facebook.com/fourtune.chen) 若有謬誤 , 煩請告知 , 新手發帖請多包涵 # :100: :muscle: :tada: :sheep: <iframe src="https://skilltree.my/c67b0d8a-9b69-47ce-a50d-c3fc60090493/promotion?w=250" width="250" style="border:none"></iframe>