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.