Pragmatic paranoia
Download
Report
Transcript Pragmatic paranoia
PRAGMATIC PARANOIA
Steven Hadfield & Anthony Rice
You can’t write perfect software
Accept it
Nobody else writes it either
Be
defensive about other people’s code
Play it safe
Design by Contract
Developed by Bertrand Meyer (Eiffel)
Use contracts to force both parties into an
agreement: caller and routine
Each party is expected to uphold their end of the
deal
Preconditions, postconditions, and class invariants
Preconditions
What the caller guarantees will be passed to the
routine
The routine’s requirements
It’s up to the calling code to make sure that the
requirements are kept
Postconditions
What the routine guarantees to return
How the world should be after the routine is done
Lazy code: require a lot, promise little in return
Class invariants
Conditions that should always be true from caller’s
perspective
Routine possibly allowed to change it temporarily
while working, but should return to previous state
Things that the routine is not allowed to change
Applies to all methods in a class
Designing with Contracts
It’s a design technique
Directly
supported by some languages
Handy if compiler can do it, but not necessary
Assertions – partially emulate DBC
Use preprocessors for languages without
Messy
and not as good, but helpful
Can be dynamically generated
Rejected
and/or negotiated
Invariants
Also applies at lower levels
Loop invariant
Making
sure something is true before and during a loop
Semantic invariants
Central
to the purpose of a task
Should be clear and unambiguous
Dead Programs Tell No Lies
If a program is going to crash, do it early
Crash with class
Provide
useful information
If the impossible happens, die as soon as possible
Everything
after the impossible happens is suspect
Assertive Programming
This can never happen…
“This
code will not be used 30 years from now, so twodigit dates are fine”
“This application will never be used abroad, so why
internationalize it?”
“count can’t be negative”
“This printf can’t fail”
Assertions
If it can’t happen, use assertions to ensure that it
won’t
Don’t use assertions as error handling, they should
just be used to check for things that should never
happen.
Void writeString(char *string){
assert(string != NULL);
Never put code that should be executed into as
assert.
Leave Assertions Turned On
Misunderstanding:
Since
they check for things that should never happen,
the are only triggered by a bug in the code. They
should be turned off when shipped to make the code
run faster.
Leave Assertions Turned On
You cannot assume that testing will find all the bugs.
Your program runs in a dangerous world.
Your first line of defense is checking for any
possible error, and your second is using assertions to
try to detect those you missed.
Assertions and Side Effects
Instead of:
While
(iter.hasMoreElements()) {
Test.ASSERT(iter.nextElement() != null);
Object obj = iter.nextElement();
Do:
While
(iter.hasMoreElements()) {
Object obj = iter.nextElement();
Test. ASSERT(obj != null);
When to Use Exceptions
Checking for every possible error can lead to some
pretty ugly code.
If the programming language supports exceptions,
you can use try catch loops to make the code much
easier to read.
What is Exceptional?
Exceptions should be reserved for unexpected
events.
They should rarely be used as the programs normal
flow.
Use Exceptions for Exceptional
Programs
An exception represents an immediate, nonlocal
transfer of control.
Using exceptions as part of normal processing will
give you all the readability and maintainability
problems of spaghetti code.
Error Handlers Are an Alternative
Error Handlers are routines that are called when an
error is detected.
These routines can handle a specific category of
errors.
How to Balance Resources
Finish What You Start
Many
developers have not consistent plan for dealing
with resource allocation and deallocation.
The routine or object that allocates a resource should
be responsible for deallocating it.
Nest Allocations
The basic pattern for resource allocation can be
extended for routines that need more than one
resource at a time.
Deallocate
resources in the opposite order in which you
allocate them.
When allocating the same set of resources in different
places in your code, always allocate them in the same
order.
Objects and Exceptions
Encapsulation of resources in classes
Instantiate that class when you need a particular
resource type.
When You Can’t Balance Resources
Commonly found in programs that use dynamic data
structures.
When you deallocate the top-level data structure:
Top-level
structure responsible for substructures.
Top-level structure is simply deallocated.
Top-level structure refuses to deallocate itself if it
contains substructures.
Choice depends on individual data structure.
Checking the Balance
Produce wrappers for each resource, and keep
track of all allocations and deallocations.
When program logic says resources will be in a
certain state you can use the wrappers to check it.