Contents
Meta
—
* still in an early stage
—
* still in an early stage
Avoid Invariants and Preconditions.
Methods typically have preconditions. Something that has to be true prior to invoking the method so it can work properly. Typical cases are parameters that may not be null
or have to be in a certain range. A solution is better the fewer preconditions there are.
Furthermore there are (class) invariants, i.e. conditions that have to be true in all observable states during the whole lifetime of an object. Typical invariants are attributes that may not be null
or have to be in a certain range, lists that have to contain certain objects with certain properties, etc. A solution is better the fewer invariants there are.
While preconditions and invariants are absolutely necessary, introducing further ones comes at a certain cost.
Not that this principle does not apply to loop invariants, control-flow invariants, etc. as there is normally no chance to avoid them. But there can be fewer or more class invariants depending on the solution.
A typical kind of defect is the violation of an invariant or a precondition. The more preconditions and invariants there are, the more possibilities there are to introduce defects. And according to Murphy's Law these possibilities will sooner or later result in defects. So it is better to avoid preconditions and invariants as this reduces the number of potential faults in the software.
null
int
instead of Integer
but not int
instead of Customer
)Keep in mind that preconditions and invariants are absolutely necessary for every software. So this principle is constantly violated. Introducing preconditions and invariants is often also done deliberately in order to simplify the code (see KISS). So the purpose of this principle is mainly to point out that there are drawbacks. By no means invariants are problematic themselves or should be entirely avoided. They just also have disadvantages.
See also section contrary principles.
Christian Rehn: A Principle Language for Object-oriented Design
Square
from Rectangle
for example adds an invariant in the subclass. LSP adds another point of view to this problem (see also rectangle-square problem).public void prettyPrintItem(List<Item> items, int index) { ... }
This method has the following preconditions:
items
may not be null
index
must be greater or equal 0
index
must be lesser than items.size()
Compare the following solution:
public void prettyPrintItem(Item item) { ... }
This is better as it just has one precondition: item
may not be null
public void downloadFile(String url) { ... }
This method has the following preconditions:
url
may not be null
url
must contain a valid URL (which is even a quite complicated precondition)Compare the following method:
public void downloadFile(URL url) { ... }
This is better since there is only one precondition: url
may not be null
Compare the following two methods:
void prettyPrint(SomeClass * obj) { ... }
void prettyPrint(SomeClass& obj) { ... }
In the second version obj
cannot be NULL
as it is a reference and not a pointer. So there is one precondition less.
A class for complex numbers should either store the real and the imaginary part or absolute value and argument but not both. If both are stored, there is the invariant that both representations result in the same complex number.
So it is better to store just one representation (e.g. the real and imaginary values) and if the other representation is needed (in this case the polar form), it can be computed. This can also be done transparently in the getter method.
All forms of caching and redundancy are typical violations of IAP. They are done in order to increase performance. But there is always the disadvantage that all copies have to be kept in sync as there is the invariant that the data may not be inconsistent throughout the copies. There are forms of caching where temporary inconsistencies are tolerated. This is slightly better in terms of IAP but nevertheless there are these consistency constraints and there is the danger of violating them, so to some degree the disadvantage is always there.
Christian Rehn: A Principle Language for Object-oriented Design
Discuss this wiki article and the principle on the corresponding talk page.