Slides to a (non-commercial) talk i gave 2011 at XPUG Rhein/Main (Germany) about how to write comprehensible code, regarding cognitive abilities of human mind.
75. public reorderBook( String isbn ){
...
if( isbn.substring( 0, 2 ).equals( ''978'' ){
pubNr = isbn.substring( 6, 10 );
}
else{
pubNr = isbn.substring( 8, 12 );
}
...
}
ISBN is NOT a String !!!
76. public interface Isbn {
public Region getRegion(){ ... }
public Integer getPublisherNumber(){ ... }
public Integer getTitelNumber(){ ... }
public Integer getChecksum(){ ... }
public boolean isValid(){ ... }
}
ISBN is a concept in its own right !!!
public reorderBook( Isbn isbn ){
...
isbn.getPublisherNumber();
...
}
78. public boolean isValidLaufzeit( Vertrag vertrag ){
GregorianCalendar start = vertrag.getStart();
GregorianCalendar end = vertrag.getEnd();
int tagesdifferenz = 0;
if (start != null && end != null) {
int startJahr = start.get(Calendar.YEAR);
int endJahr = end.get(Calendar.YEAR);
int tageImStartJahr = start.get(Calendar.DAY_OF_YEAR);
int tageImEndJahr = end.get(Calendar.DAY_OF_YEAR);
int aktuellesJahr = startJahr;
while (aktuellesJahr <= endJahr) {
if (aktuellesJahr == startJahr) {
if (aktuellesJahr == endJahr) {
tagesdifferenz += tageImEndJahr - tageImStartJahr;
} else {
tagesdifferenz += start.isLeapYear(startJahr) ?
(366 - tageImStartJahr) : (365 - tageImStartJahr);
}
} else if (aktuellesJahr == endJahr) {
tagesdifferenz += tageImEndJahr;
} else {
tagesdifferenz += start.isLeapYear(aktuellesJahr) ? 366 : 365;
}
aktuellesJahr++;
}
}
return tagesdifferenz > 365 && tagesdifferenz < 999;
}
79. public void createOrder( int itemId, Date shippingDate ){
Date today = new Date();
long start = today.getTime();
long end = shippingDate.getTime();
BigDecimal diff = new BigDecimal( start - end );
int days = diff.divideToIntegralValue(
new BigDecimal( 1000 * 60 * 60 * 24 ) ).intValue();
if( days > 14 ) rejectOrder();
// ...
}
98. Is this a Composite ?
AtLeastOneAuthProvider ''authenticate'
LdapAuthProvider DatabaseAuth. UnanimousAuthProvider
''authenticate' ''authenticate'
CertificateAuth. AccessAuth.
''authenticate' ''authenticate'
99. ... and this ?
CEO ''salary'
Employee Employee CIO
''salary' ''salary'
Employee Employee
''salary' ''salary'
100.
101. Collection
generalization
List Set Bag
Queue Stack
< discrimination >
FIFO LIFO
102. public static Integer sum( Stack<Integer> vals ){
int sum = 0;
for( int val : vals ) sum += val;
return sum;
}
103. public static Integer sum( Stack<Integer> vals ){
int sum = 0;
for( int val : vals ) sum += val;
return sum;
}
sum( new Stack<Integer>(){{ push(1); push(2); push(3); }};
sum( new ArrayList<Integer>(){{ add(1); add(2); add(3) }};
104. public static Integer sum( List<Integer> vals ){
int sum = 0;
for( int val : vals ) sum += val;
return sum;
}
sum( new Stack<Integer>(){{ push(1); push(2); push(3); }};
sum( new ArrayList<Integer>(){{ add(1); add(2); add(3) }};
sum( new HashSet<Integer>(){{ add(1); add(2); add(3) }};
105. public static Integer sum( Collection<Integer> vals ){
int sum = 0;
for( int val : vals ) sum += val;
return sum;
}
sum( new Stack<Integer>(){{ push(1); push(2); push(3); }};
sum( new ArrayList<Integer>(){{ add(1); add(2); add(3) }};
sum( new HashSet<Integer>(){{ add(1); add(2); add(3) }};
113. public static List<Integer> multiplesOf( int factor, int limit ){
List<Integer> collect = new ArrayList<Integer>();
for( int i = 1; i * factor <= limit; i++ ){
collect.add( i * factor );
}
return collect;
}
vs.
public static Set<Integer> multiplesOf( int factor, int limit ){
Set<Integer> collect = new HashSet<Integer>();
for( int i = 1; i * factor <= limit; i++ ){
collect.add( i * factor );
}
return collect;
}
114. public static List<Integer> multiplesOf( int[] factors, int limit ){
List<Integer> collect = new ArrayList<Integer>();
for( int factor : factors ){
for( int i = 1; i * factor <= limit; i++ ){
collect.add( i * factor );
}
}
return collect;
}
115. public static Set<Integer> multiplesOf( int[] factors, int limit ){
Set<Integer> collect = new HashSet<Integer>();
for( int factor : factors ){
for( int i = 1; i * factor <= limit; i++ ){
collect.add( i * factor );
}
}
return collect;
}
127. ... do you recognize the underlying concept ?
interface Stepper<T>{
public boolean isExhausted();
public void step();
public T getCurrent()
}
128. ... do you recognize the underlying concept ?
interface ElementSupplier<T>{
public boolean hasMoreElements();
T nextElement();
}
129. ... do you recognize the underlying concept ?
interface ElementConsumer{
public void observe( BigElement e );
public void calculate( AnotherElement e );
public void extract( YetAnotherElement );
}
130. ... do you recognize the underlying concept ?
interface ElementInspector{
public void inspect( BigElement e );
public void inspect( AnotherElement e );
public void inspect( YetAnotherElement );
}
131. ... do you recognize the underlying concept ?
interface ElementVisitor{
public void visit( BigElement e );
public void visit( AnotherElement e );
public void visit( YetAnotherElement );
}
132. Language
date.compareTo( otherDate ) < 0
vs.
date.isBefore( otherDate )
136. Verifiable Specifications
Stack stack = is(
new DescriptionOf <Stack>(){
public Stack isDescribedAs(){
Stack<String> stack = new Stack<String>();
stack.push( foo );
stack.push( bar );
return stack; } } );
it( "should contain foo" );
state( stack ).should( contain( foo ) );
it( "should contain bar" );
state( stack ).should( contain( bar ) );
it( "should return bar when calling pop the first time" );
state( stack.pop() ).should( returning( bar ) );
it( "should return foo when calling pop the second time" );
stack.pop();
state( stack.pop() ).should( returning( foo ) );
it( "should be empty after popping the two elements" );
stack.pop();
stack.pop();
state( stack ).should( be ( empty() ) );
137. Design by Contract
@Invariant( "this.size >= 0 and this.size <= this.capazity" )
public interface Stack { ... }
@Postcondition( "return > 0" )
public int getCapacity();
public int getSize();
@Precondition( "elem not null and this.size < this.capacity" )
@Postcondition( "elem == this.top and this.size == old:this.size + 1" )
public void push( Object elem );
@Postcondition( "this.top == old:this.top ) " )
public Object getTop();
@Postcondition(
"(old:this.size>0) ==> (return == old:this.top and this.size == old:this.size - 1)")
public Object pop();
...
}
138. Liskovsubtype of T, then objects of type T in a
''if S is a
Substitution Principle
program may be replaced with objects of type S
without altering any of the desirable properties''