CSC/ECE 517 Fall 2009/wiki3 9 rp: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
 
No edit summary
Line 1: Line 1:
= The Non-Redundancy Principle =
= The Non-Redundancy Principle =


In Bertrand Meyer's ''Object Oriented Software Construction'', he
In Bertrand Meyer's ''Object Oriented Software Construction'', he outlines many principles to increase reusability by managing complexity in software design.  Some of these apply primarily to object oriented programming, primarily the principles dedicated to abstract data types.  Most of the principles, however, apply to programming generally.  The first five discussed in the book are often discussed in articles (the "Open-Close Principle" perhaps being the most popular), but equally important principles are discussed later in the book as well.  One such principle, presented in the section on ''Contracting For Software Reliability'', is called The Non-Redundancy Principle.
outlines many principles to increase reusability by managing
complexity in software design.  Some of these apply primarily to
object oriented programming, primarily the principles dedicated to
abstract data types.  Most of the principles, however, apply to
programming generally.  The first five discussed in the book are often
discussed in articles (the "Open-Close Principle" perhaps being the
most popular), but equally important principles are discussed later in
the book as well.  One such principle, presented in the section on
''Contracting For Software Reliability'', is called The Non-Redundancy
Principle.


== Definition ==
== Definition ==


As with all principles presented in ''Object Oriented Software
As with all principles presented in ''Object Oriented Software Construction'', the principle itself is quite terse:
Construction'', the principle itself is quite terse:


<blockquote> Under no circumstances shall the body of a routine ever
<blockquote> Under no circumstances shall the body of a routine ever test for the routine's precondition.  </blockquote>
test for the routine's precondition.  </blockquote>


As simple as this may seem on first blush, it has extensive
As simple as this may seem on first blush, it has extensive implications.
implications.


Before we discuss the implications, it is proper to provide a bit of
Before we discuss the implications, it is proper to provide a bit of context regarding preconditions, postconditions and programming by contract.
context regarding preconditions, postconditions and programming by
contract.


== Context ==
== Context ==


Meyer outlined the notion of ''programming by contract'', which boils
Meyer outlined the notion of ''programming by contract'', which boils down to a methodology to enforce software modularity by clearly defining the relationships between various components, much in the same way relationships between individuals and/or companies are formalized in contracts.
down to a methodology to enforce software modularity by clearly
defining the relationships between various components, much in the
same way relationships between individuals and/or companies are
formalized in contracts.


In Chapter 11, Meyer indicates that for each party in the contract,
In Chapter 11, Meyer indicates that for each party in the contract, the aspects of the contract include:
the aspects of the contract include:


* Rights
* Rights
Line 44: Line 24:
* Postconditions
* Postconditions


In short, these indicate what is expected of the ''supplier'' and the
In short, these indicate what is expected of the ''supplier'' and the ''client'' (terms describing the roles of objects that are party to the contract).  Specifically, a ''precondition'' is a minimum criteria that must be satisfied on the part of the client for the contract to be valid.  The heart of the Non-Redundancy Principle is ''who'' checks that the preconditions are satisfied, and ''when'' are those checks made.
''client'' (terms describing the roles of objects that are party to
the contract).  Specifically, a ''precondition'' is a minimum criteria
that must be satisfied on the part of the client for the contract to
be valid.  The heart of the Non-Redundancy Principle is ''who'' checks
that the preconditions are satisfied, and ''when'' are those checks
made.


It must be decided whether the client or the supplier of a service
It must be decided whether the client or the supplier of a service should enforce the preconditions.  Once that is made clear, the software designer must decide when the precondition will be enforced, and once it is enforced, it should never be checked.
should enforce the preconditions.  Once that is made clear, the
software designer must decide when the precondition will be enforced,
and once it is enforced, it should never be checked.


Meyer goes to some length to justify this position, which flies in the
Meyer goes to some length to justify this position, which flies in the face of the defensive programming mantra, which generally encourages as much checking as possible, ostensibly to help eliminate errors "just in case".  As we will see in the following sections, and as Meyer describes, it is difficult to justify this approach, purly on the grounds that such redundant checking inordinately increases the complexity of the software.
face of the defensive programming mantra, which generally encourages
as much checking as possible, ostensibly to help eliminate errors
"just in case".  As we will see in the following sections, and as
Meyer describes, it is difficult to justify this approach, purly on
the grounds that such redundant checking inordinately increases the
complexity of the software.


== Implications ==
== Implications ==


There are a variety of implications that emerge from the
There are a variety of implications that emerge from the Non-Redundancy Principle.
Non-Redundancy Principle.


=== DRY Principle ===
=== DRY Principle ===


A common mantra in programming is "Don't Repeat Yourself" or simply
A common mantra in programming is "Don't Repeat Yourself" or simply "DRY" for short.  In it's simplest form, the Non-Redundancy Principle is a specialization of DRY, in that it prohibits developers from repeating themselves.
"DRY" for short.  In it's simplest form, the Non-Redundancy Principle
is a specialization of DRY, in that it prohibits developers from
repeating themselves.


Consider the example that Meyer uses of a function responsible for
Consider the example that Meyer uses of a function responsible for returning a real positive square root of a number.  In Java, such a function might look like:
returning a real positive square root of a number.  In Java, such a function
might look like:


  /**
  /**
Line 88: Line 47:
  }
  }


What happens if the number passed in is negative?  Will the method
What happens if the number passed in is negative?  Will the method return a real square root?  We have specified in the supplier (in this case, the method called "sqrt") is obligated to return a positive real square root.  By specifying a precondition that the input must be greater than or equal to zero, we now also qualify that obligation by imposing it only if the precondition is satisfied.   
return a real square root?  We have specified in the supplier (in this
case, the method called "sqrt") is obligated to return a positive real
square root.  By specifying a precondition that the input must be
greater than or equal to zero, we now also qualify that obligation by
imposing it only if the precondition is satisfied.   


  /**
  /**
Line 103: Line 57:
  }
  }


Now we have a precondition.  But what does all this have to do with
Now we have a precondition.  But what does all this have to do with the Non-Redundancy Principle?
the Non-Redundancy Principle?


It might be tempting to then write this:
It might be tempting to then write this:
Line 117: Line 70:
  }
  }


But, according to the Non-Redundancy Principle, this is prohibited!
But, according to the Non-Redundancy Principle, this is prohibited! Why?  Well, what does Math.sqrt do?  Does it also check for a value less than zero?  It turns out that it does.  But the point here is that if we use the code directly above this paragraph, our system now checkes for numbers less than zero ''twice''.  Not only have we repeated ourselves, but we have increased the complexity of the code, which brings us to how the Non-Redundancy Principle reduces code complexity.
Why?  Well, what does Math.sqrt do?  Does it also check for a value
less than zero?  It turns out that it does.  But the point here is
that if we use the code directly above this paragraph, our system now
checkes for numbers less than zero ''twice''.  Not only have we
repeated ourselves, but we have increased the complexity of the code,
which brings us to how the Non-Redundancy Principle reduces code
complexity.


=== Code Complexity ===
=== Code Complexity ===  


One way to measure code complexity is through [http://www.mccabe.com/iq_research_iqgloss.htm#cyclomatic cyclomatic complexity] (sometimes called the ''McCabe Number'').  Simply put, cyclomatic complexity measures the number of different paths through a piece of code.  It is often cited as a good measure of how maintainable a piece of code is, and certainly has an impact on how burdensome testing will be.  In the example above:
public double sqrt(double d) {
  if (d < 0) throw new IllegalArgumentException("Input must be greater than or equal to zero.");
  return Math.sqrt(d);
}
We can immediately see that adding the check for the precondition to the method added an additional exit from the method, namely, the method can now throw an IllegalArgumentExecetion.  Taken singly, this may not seem like a big deal, but imagine methods with two or more preconditions, and imagine every method in the system starts checking for each.  On a systemic scale, redundant checking vastly increases the code bulk, complexity, and testing burden of the system.


=== Run-time versus Compile-time Errors ===
=== Run-time versus Compile-time Errors ===

Revision as of 07:38, 18 November 2009

The Non-Redundancy Principle

In Bertrand Meyer's Object Oriented Software Construction, he outlines many principles to increase reusability by managing complexity in software design. Some of these apply primarily to object oriented programming, primarily the principles dedicated to abstract data types. Most of the principles, however, apply to programming generally. The first five discussed in the book are often discussed in articles (the "Open-Close Principle" perhaps being the most popular), but equally important principles are discussed later in the book as well. One such principle, presented in the section on Contracting For Software Reliability, is called The Non-Redundancy Principle.

Definition

As with all principles presented in Object Oriented Software Construction, the principle itself is quite terse:

Under no circumstances shall the body of a routine ever test for the routine's precondition.

As simple as this may seem on first blush, it has extensive implications.

Before we discuss the implications, it is proper to provide a bit of context regarding preconditions, postconditions and programming by contract.

Context

Meyer outlined the notion of programming by contract, which boils down to a methodology to enforce software modularity by clearly defining the relationships between various components, much in the same way relationships between individuals and/or companies are formalized in contracts.

In Chapter 11, Meyer indicates that for each party in the contract, the aspects of the contract include:

  • Rights
  • Obligations
  • Preconditions
  • Postconditions

In short, these indicate what is expected of the supplier and the client (terms describing the roles of objects that are party to the contract). Specifically, a precondition is a minimum criteria that must be satisfied on the part of the client for the contract to be valid. The heart of the Non-Redundancy Principle is who checks that the preconditions are satisfied, and when are those checks made.

It must be decided whether the client or the supplier of a service should enforce the preconditions. Once that is made clear, the software designer must decide when the precondition will be enforced, and once it is enforced, it should never be checked.

Meyer goes to some length to justify this position, which flies in the face of the defensive programming mantra, which generally encourages as much checking as possible, ostensibly to help eliminate errors "just in case". As we will see in the following sections, and as Meyer describes, it is difficult to justify this approach, purly on the grounds that such redundant checking inordinately increases the complexity of the software.

Implications

There are a variety of implications that emerge from the Non-Redundancy Principle.

DRY Principle

A common mantra in programming is "Don't Repeat Yourself" or simply "DRY" for short. In it's simplest form, the Non-Redundancy Principle is a specialization of DRY, in that it prohibits developers from repeating themselves.

Consider the example that Meyer uses of a function responsible for returning a real positive square root of a number. In Java, such a function might look like:

/**
 * Returns the postive real square root of the input, d.
 */
public double sqrt(double d) {
  return Math.sqrt(d);
}

What happens if the number passed in is negative? Will the method return a real square root? We have specified in the supplier (in this case, the method called "sqrt") is obligated to return a positive real square root. By specifying a precondition that the input must be greater than or equal to zero, we now also qualify that obligation by imposing it only if the precondition is satisfied.

/**
 * Returns the postive real square root of the input, d.
 * Precondition: input d >= 0
 */
public double sqrt(double d) {
  return Math.sqrt(d);
}

Now we have a precondition. But what does all this have to do with the Non-Redundancy Principle?

It might be tempting to then write this:

/**
 * Returns the postive real square root of the input, d.
 * Precondition: input d >= 0
 */
public double sqrt(double d) {
  if (d < 0) throw new IllegalArgumentException("Input must be greater than or equal to zero.");
  return Math.sqrt(d);
}

But, according to the Non-Redundancy Principle, this is prohibited! Why? Well, what does Math.sqrt do? Does it also check for a value less than zero? It turns out that it does. But the point here is that if we use the code directly above this paragraph, our system now checkes for numbers less than zero twice. Not only have we repeated ourselves, but we have increased the complexity of the code, which brings us to how the Non-Redundancy Principle reduces code complexity.

Code Complexity

One way to measure code complexity is through cyclomatic complexity (sometimes called the McCabe Number). Simply put, cyclomatic complexity measures the number of different paths through a piece of code. It is often cited as a good measure of how maintainable a piece of code is, and certainly has an impact on how burdensome testing will be. In the example above:

public double sqrt(double d) {
  if (d < 0) throw new IllegalArgumentException("Input must be greater than or equal to zero.");
  return Math.sqrt(d);
}

We can immediately see that adding the check for the precondition to the method added an additional exit from the method, namely, the method can now throw an IllegalArgumentExecetion. Taken singly, this may not seem like a big deal, but imagine methods with two or more preconditions, and imagine every method in the system starts checking for each. On a systemic scale, redundant checking vastly increases the code bulk, complexity, and testing burden of the system.

Run-time versus Compile-time Errors