High-Quality Programming Code Construction

Download Report

Transcript High-Quality Programming Code Construction

Defensive Programming and Exceptions

How to Design Error Steady Code Ivaylo Bratoev Telerik Corporation www.telerik.com

Defensive Programming

Using Assertions and Exceptions Correctly

Protecting from invalid input

“Garbage in, garbage out.” – NO!

Garbage in - nothing out, error message out or no garbage allowed in

Check the values of all data from external sources (a user, a file, internet, etc.)

3

Protecting from invalid input

Check method preconditions – parameters, object state

Check method postconditions – what is guaranteed to the caller string Substring(string str, int startIndex, int length) { REQUIRE(str != NULL); preconditions REQUIRE(startIndex >= str.Length); REQUIRE(startIndex + count > str.Lenght); string result = … main logic } ENSURE(result.Length == length); postconditions.

4

Assertions

A statement placed in a program to indicate that must always be true at that place void GetAvarageStudentGrade() { Debug.Assert(studentGrades.Count > 0, “student grades are not initialized”); return studentGrades.Avarage(); }

Failed assertion indicates a fatal error in the program (usually unrecoverable)

Assertions should fail loud

5

Assertions

Assertions are used during development , they are removed during production compilation

Use assertions for conditions that should never occur

Avoid putting executable code in assertions assert PerformAction() : “Couldn't perform action”

Won’t be compiled in production. Better: bool actionedPerformed = PerformAction(); assert actionedPerformed : “Couldn't perform action”

6

Assertions

Use assertions to document preconditions and postconditions that must be true private Student GetRegisteredStudent(int id) { Debug.Assert(id > 0); Student student = registeredStudents[id]; Debug.Assert(student.IsRegistered); }

For highly robust code, assert, and then handle the error anyway

Assertions check for bugs in code

7

Error Handling Techniques

How do you handle errors that you do expect to occur?

Depends on the situation. Examples:

Return a neutral value

Return the same answer as the previous time

Log a warning message to a file

Return an error code

Call an error processing method/object

Display an error message

Shutdown

8

Robustness vs. Correctness

How will you handle error while calculating single pixel color in a computer game?

How will you handle error while calculating single pixel color in a X-Ray software?

Correctness - never returning an inaccurate result.

Robustness - always trying to do something that will allow the software to keep running.

9

Error handling strategy

Choose your error handling strategy and follow it consistently

Strongly consider using exceptions

10

Exceptions

Exceptions are a specific means by which code can pass along errors or exceptional events to the code that called it.

Methods throw exceptions: public void ReadInput(string input) { if(input == null) { throw new ArgumentNullException(“input”); } }

11

Exceptions

Use try-catch block to handle exceptions: void playNextTurn() { try { Exception thrown here … readInput(input); Code here won’t be executed … } catch(ArgumentNullException e) { console.printLine(“Hello from catch!”); } }

12

Exceptions

Use finally to execute code even if exception occurs (not supported in C++): void playNextTurn() { try { … readInput(input); Exception thrown here Code here is always executed … } finally { console.printLine(“Hello from finally!”); } }

Perfect place to perform cleanup for any resources allocated in the try block.

13

Exceptions

Use exceptions to notify other parts of the program about errors that should not be ignored

Throw an exception only for conditions that are truly exceptional

Should I throw an exception when checking for user name and password?

Don’t use exceptions as control flow mechanisms

14

Exceptions

Throw exceptions at the right level of abstraction class Employee { … public TaxId getTaxId() throws EOFException { … } } class Employee { … public TaxId getTaxId() throws EmployeeDataNotAvailable { … } }

15

Exceptions

Use descriptive error messages

Incorrect example:

Example: throw new Exception("Error!"); throw new ArgumentException("The speed should be a number " + "between " + MIN_SPEED + " and " + MAX_SPEED + ".");

Avoid empty catch blocks try { … // lots of code … } catch(Exception ex){ }

16

Exceptions

Always include the exception cause when throwing a new exception try { WithdrawMoney(account, amount); } catch (DatabaseException dbex) { throw new WithdrawException(String.Format( "Can not withdraw the amount {0} from acoount {1}", amount, account), dbex); } We include in the exceptions chain the original source of the problem.

17

Exceptions

Catch only exceptions that you are capable to process correctly

Do not catch all exceptions

Incorrect example: try { ReadSomeFile(); } catch { Console.WriteLine("File not found!"); }

What about OutOfMemoryException ?

18

Exceptions

Have an exception handling strategy for unexpected/unhandled exception:

Consider logging (log4net, log4j, log4cplus).

Display to the end users only messages that they could understand or

19

Assertions vs Exceptions

Exceptions are announcements about error condition or unusual event

Inform the caller about error or exceptional event

Can be caught and application can continue working

Assertions are fatal errors

Assertions always indicate bugs in the code

Can not be caught and processed

Application can’t continue in case of failed assertion

When in doubt – throw exception

20

Assertions vs Exceptions

string Substring(string str, int startIndex, int length) { if (str == null) { throw new NullReferenceException("Str is null."); } if (startIndex >= str.Length) { Check the input and preconditions.

throw new ArgumentException( "Invalid startIndex:" + startIndex); } if (startIndex + count > str.Length) { throw new ArgumentException("Invalid length:" + length); } … Perform the method main logic.

Debug.Assert(result.Length == length); Check the postconditions.

}

21

Error Barricades

Barricade your program to contain the damage caused by errors

Behind the barricade is “safe” area - data is valid

Validate data crossing the boundary

Consider same approach for class design

Public methods validate the data

Private methods assume the data is safe

Consider using exceptions for public methods and assertions for private

22

Debugging Aids

Don’t automatically apply production constraints to the development version

Be willing to trade speed and resource usage during development

Introduce debugging aids early

Make errors obvious during development

Asserts should abort the program

Unhandled exceptions should not be hidden

Plan for removing debugging aids

23

Being Defensive About Defensive Programming

How much defensive programming to leave in production code

Remove code that results in hard crashes

Leave in code that checks for important errors

Log errors for your technical support personnel

See that the error messages you leave in are friendly

Too much defensive programming is not good – strive for balance

24

Defensive Programming

Questions?

http://academy.telerik.com