Software Craftsmanship

Defensive Programming

Defense Against the Dark Arts

A Bit of Healthy Paranoia

"Everyone knows that they personally are the only good driver on Earth. The rest of the world is out there to get them, blowing through stop signs, weaving between lanes, not indicating turns, talking on the telephone, reading the paper, and just generally not living up to our standards. So we drive defensively. We look out for trouble before it happens, anticipate the unexpected, and never put ourselves into a position from which we can't extricate ourselves."

- Pragmatic Programmer

Don't trust future you either!

Which brings us to the the first rule of Defensive Programming

"The best defense is a good offense"

Offensive Programming

Immediate and Visible Failure!

Offensive Programming

"When your code discovers that something that was supposed to be impossible just happened, your program is no longer viable. Anything it does from this point forward becomes suspect, so terminate it as soon as possible."

-Pragmatic Programmer

 

Common mistakes.

  1. Empty catch blocks.
  2. Setting default values when none are specified. 

What's wrong?

Text

Fixed

Offensive Programming and

Unreliable Input

Pulling in input from an external source is about as unreliable as you can get.

 

Sometimes you can't simply exit the program when something unexpected happens, you have to deal with it.

Isolate such situations. For example when ingesting data, either convert that data into usable unit of data or drop them.

SQL Injection

Heartbeat Vulnerability

Heartbeat Vulnerability

Design By Contract

Define the rights and responsibilities of your code to the consumer.

 

Preconditions

  • Conditions the caller and application state must meet for the function to be relevant.

Postconditions

  • The consistent, defined change of state that always occurs when the preconditions are true. 

Invariants

  • Conditions that remain the same before and after the method is called.

Design By Contract

Preconditions should be strict and postconditions should be minimal!

Preconditions

- (void)saveRememberMeData
{
    assert(_maskedUsername != nil
            && _encryptedUsername != nil
            && _tempPassword != nil);

    if (!_rememberMe) return;

    C1KeychainWrangler *keychain = [C1KeychainWrangler sharedWrangler];
    
    keychain[ccwMaskedUsernameKey] = _maskedUsername;
    keychain[ccwEncryptedUsernameKey] = _encryptedUsername;
    keychain[ccwEncryptedPasswordKey] = _tempPassword;

...

Postconditions

public class UrlResource extends AbstractFileResolvingResource {

	/**
	 * This implementation opens an InputStream for the given URL.
	 * <p>It sets the {@code useCaches} flag to {@code false},
	 * mainly to avoid jar file locking on Windows.
	 * @see java.net.URL#openConnection()
	 * @see java.net.URLConnection#setUseCaches(boolean)
	 * @see java.net.URLConnection#getInputStream()
	 */
	@Override
	public InputStream getInputStream() throws IOException {


Unit Tests

Stating your intentions

Strictly speaking, the contracts in Design by Contract are supposed to be run time definitions of the pre, post, and invariants. However, comprehensively testing the postconditions at runtime is often not feasible.

 

Unit tests (because they are not runtime) are not a replacement for postconditions; however, they can state intent. 

For Example

public class FakeBankWebService : IBankWebService
{
    public bool BillUser(string creditCard)
    {
        return false; // our fake object always says billing failed
    }
}

public void TestUserIsRemoved()
{
    IBankWebService fakeBank = FakeBankWebService();

    AccountServices services = new AccountServices(fakeBank);

    string registrationResult = services.RegisterUser("test_username");

    Assert.AreEqual("Your credit card was declined", registrationResult);
}

Taking a Step Back

Why is Defensive Programming so Important?

  • Developers often forget to take into account the consumers of their code.

 

 

A Real World Example

/**
 * Sets the seed of this random number generator using a single
 * {@code long} seed. The general contract of {@code setSeed} is
 * that it alters the state of this random number generator object
 * so as to be in exactly the same state as if it had just been
 * created with the argument {@code seed} as a seed. The method
 * {@code setSeed} is implemented by class {@code Random} by
 * atomically updating the seed to
 *  <pre>{@code (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1)}</pre>
 * and clearing the {@code haveNextNextGaussian} flag used by {@link
 * #nextGaussian}.
 *
 * <p>The implementation of {@code setSeed} by class {@code Random}
 * happens to use only 48 bits of the given seed. In general, however,
 * an overriding method may use all 64 bits of the {@code long}
 * argument as a seed value.
 *
 * @param seed the initial seed
 */
synchronized public void setSeed(long seed) {
    this.seed.set(initialScramble(seed));
    haveNextNextGaussian = false;
}

http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/tip/src/share/classes/java/util/Random.java

Test Driven Development

Why is Defensive Programming so Important?

  • Developers often forget to take into account the consumers of their code.

 

 

Writing code from the consumer's view point. 

Copy of Software Craftsmanship - Defensive Programming (Alyssa)

By cof_softwarecraftsmanship

Copy of Software Craftsmanship - Defensive Programming (Alyssa)

2016 - Day 2.2

  • 351