User Tools

Site Tools


principles:invariant_avoidance_principle

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Next revisionBoth sides next revision
principles:invariant_avoidance_principle [2021-09-02 12:37] – old revision restored (2021-05-11 21:58) 65.21.179.175principles:invariant_avoidance_principle [2021-09-02 20:09] – old revision restored (2021-03-27 09:33) 65.21.179.175
Line 10: Line 10:
  
 ===== Principle Statement ===== ===== Principle Statement =====
 +
 +Avoid Invariants and Preconditions.
  
  
Line 19: Line 21:
  
 ===== Strategies ===== ===== Strategies =====
 +
 +  * If the language supports that, use references which cannot be ''null''
 +    * In C++ use references instead of pointers (see [[#example 3: C++ references]])
 +    * In Java use primitive types instead of their object wrappers (''int'' instead of ''Integer'' but not ''int'' instead of ''Customer'')
 +  * Use [[patterns:value objects]] instead of primitive types (see [[#example 2: string preconditions]])
 +  * Avoid duplication of information. If the same information is stored in different places (maybe in different formats), the values may get out of sync (see also [[Don't repeat Yourself|DRY]]). This also applies to caching.
 +
 +
 +===== Caveats =====
 +
 +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 [[Keep It Simple Stupid|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]].
  
  
 ===== Origin ===== ===== Origin =====
 +
 +This principle is newly introduced here.
  
  
 ===== Evidence ===== ===== Evidence =====
 /* Comment out what is not applicable and explain the rest: */ /* Comment out what is not applicable and explain the rest: */
-/*+
   * [[wiki:Proposed]]   * [[wiki:Proposed]]
 +
 +/*
   * [[wiki:Examined]]   * [[wiki:Examined]]
   * [[wiki:Accepted]]   * [[wiki:Accepted]]
Line 37: Line 56:
 ==== Generalizations ==== ==== Generalizations ====
  
-  * [[principles:Don't Repeat Yourself]]+  * [[Murphy's Law]] (ML): ML states that an invariant will eventually be broken. So IAP is the application of ML to invariants.
  
 ==== Specializations ==== ==== Specializations ====
Line 43: Line 62:
 ==== Contrary Principles ==== ==== Contrary Principles ====
  
-  * **[[principles:Keep It Simple Stupid]]**+  * **[[Keep It Simple Stupid]] (KISS)**: Adding an invariant typically makes the code easier, as it can be assumed that the invariant holds. In fact that is often the very purpose if introducing invariants: Either they make the design easier or they are inevitable. Otherwise they should be avoided.
  
 ==== Complementary Principles ==== ==== Complementary Principles ====
  
-  * [[principles:Information Hiding/Encapsulation]] +  * [[Information Hiding/Encapsulation]] (IH/E): When an invariant cannot be avoided, it should at least be encapsulated. 
-  * [[principles:Liskov Substitution Principle]] +  * [[Liskov Substitution Principle]] (LSP): Invariants can also be broken by subtypes. LSP tells that invariants may only be strengthened by subtypes, so they are not broken. FIXME 
-  * [[principles:Fail Fast]]+  * [[Fail Fast]] (FF): Breaking an invariant is a defect. And in such a case the software should fail fast. 
 +  * [[Don't Repeat Yourself]] (DRY): Duplication of information, like having the same data in different representations or like caching values, creates invariants. So an invariant sometimes is a hidden DRY violation.
  
 ==== Principle Collections ==== ==== Principle Collections ====
Line 56: Line 76:
  
  
-===== Example =====+===== Examples ===== 
 + 
 +==== Example 1: Index Preconditions ==== 
 + 
 +<code java> 
 +public void prettyPrintItem(List<Item> items, int index) 
 +
 +  ... 
 +
 +</code> 
 + 
 +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: 
 + 
 +<code java> 
 +public void prettyPrintItem(Item item) 
 +
 +  ... 
 +
 +</code> 
 + 
 +This is better as it just has one precondition: ''item'' may not be ''null'' 
 + 
 + 
 +==== Example 2: String Preconditions ==== 
 + 
 +<code java> 
 +public void downloadFile(String url) 
 +
 +  ... 
 +
 +</code> 
 + 
 +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: 
 + 
 +<code java> 
 +public void downloadFile(URL url) 
 +
 +  ... 
 +
 +</code> 
 + 
 +This is better since there is only one precondition: ''url'' may not be ''null'' 
 + 
 +==== Example 3: C++ References ==== 
 + 
 +Sompare the following two methods: 
 + 
 +<code c++> 
 +void prettyPrint(SomeClass * obj) 
 +
 +  ... 
 +
 +</code> 
 + 
 +<code c++> 
 +void prettyPrint(SomeClass& obj) 
 +
 +  ... 
 +
 +</code> 
 + 
 +In the second version ''obj'' cannot be ''NULL'' as it is a reference and not a pointer. So there is one precondition less. 
 + 
 + 
 +==== Example 4: DRY ==== 
 + 
 +A class for [[wp>complex numbers]] should either store the real and the imaginary part or absolute value and argument but not both. The values which are not stored can be computed in the getter method.
  
  
principles/invariant_avoidance_principle.txt · Last modified: 2021-10-18 21:53 by christian