Donnerstag, 8. November 2012

Abstraction

Introducing Java Generics in Java 5 has been a big deal for Java developers. Avoid failures at runtime is the biggest challenge in software development. The best solution to avoid failures is to detect errors early at compile time. The compile time type check of generic collections is the real benefit of this Java feature. Get rid of the type casts  necessary by using legacy collections simplifies the development of software in the generic context.

Generics work by erasure which can be a weakness. The genius may use a leak to break the compile time type check by mixing legacy collections with generic collections. On the other hand the inexperienced programmer could make a programming error which breaks a generic collection as well. Anyway, we have the iron-cast guarantee and we know what we do, therefore we are safe. 

The reason to build Generics on erasure is the binary compatibility to legacy collections.  This reduces the migration effort from earlier Java releases to Java 5 software to zero. The possibilites range from using legacy collections with or without Generics and vice versa. Using Generics seems to be difficult. Programmers must learn some rules to have fun with Generics. One famous rule is the get-put-principle. Maurice Naftalin and Philip Wadler documented this rule in the book "Java Generics and Collections". Do you know that rule? Remember or learn:  extends = get, super = put and no wildcard get and put. Isn't it a funny gotcha.

Regarding the requirements of clean code, Generics fulfill the criteria for writing self-explanatory source code. Well, that sounds good, but I must admit it is only true when you have learned all these rules which can sometimes mutate to brain burner. 

Interesting is the influence of abstraction in case of Generics related to data. Why not abstract over behavior in the same way Generics abstract over data? First it seems we have a big gap. But we are already able to abstract over behavior. We know and use the Strategy Pattern (GoF-Pattern) and the possible implementation by using an anonymous class which can be threat as a function object (Joshua Bloch "Effective Java"). A function object can be used to implement the requirements of behavior abstraction which leads to Lamda expressions. The experienced programmer will say no: function objects are a similar technique but weaker compared to Lamda expressions and less readable. Again, that sounds good. But how about that little rules, we already know from Generics?! Ok, we will see and learn these gotchas.

 Spot on to light the following excerpt:

Generics allowed developers to better abstraction over types, the goal of Lamda is to help developer better abstract over behavior. [Brian Goetz, Oracle’s Java Language Architect]
 
Wow! But what’s behind that excerpt? The idea is simple to threat a chunk of code like a piece of data. Describing and characterizing a method in the same way in which you would declare and use a variable is a real benefit of Lamda. The possibility for passing a Lamda expression into a method like an ordinary type will fundamentally change the development of Java software.


I’m looking forward to Java 8 and the features which improve the Java developer toolset. This toolset has additional features like the virtual extension methods which provides to implement default methods for interfaces. Default methods for interfaces mean methods with a body! That's sounds strange but why not? It is simply the support  for interface evolution to maintain binary compatibility with classes already compiled with older interface versions. Older binaries work with the new default interface methods without the requirement of recompilation. Great, no more nightmares with public interfaces.

Thank you for your attention! See you next time! I promise to publish more source code next time to discuss Java topics which is clearer than plain text.

Sonntag, 14. Oktober 2012

Armed against breaking Liskov

Software is generally based on contracts which are declared by interfaces and abstract base classes. The danger in OOP is to break the Liskov Substitution Principle (LSP) during implementing a contract in a class hierarchy. We remember: Liskov provides the correct way to implement subtyping without "the must" to modify classes during extending the class hierarchy. This is only the short version of the story. We know that Liskov has a deeper sight which describes the expected behaviour of subclasses in relationship to their base classes. Extensions of a class hierarchy are a cornerstore of OOP which is based on inheritance and ploymorphism. Therefore, be careful at design time of a class hierarchy by following Liskov.

There are several solutions to avoid breaking Liskov. The first solution is to use delegate instead of inheritance. Favour Composition over Inheritance (FCoI) is  the proper CCD principle for this case. Another practical way to ensure that Liskov is satisfied is to use Design By Contract (DBC) which is not a CCD principle. In the CCD community we discussed hard whether DBC should be part of the CCD universe. The Result of the discussions was that DBC is not a typical CCD  principle these days. The pronounciation lays on “these days”. The range of opinions were from "we need DBC at runtime to ensure the correct implementation of contracts" to "DBC is not necessary since we use Unit-Tests in combination with agile methods (TDD) in the software development process". My personal opinion was and still is that DBC is worth to be a CCD principle. With  a DBC framework on board the conditions to fulfill a contract are expressed at runtime (such as during testing) which in my opinion is a honest benefit. 

Anyway, DBC helps to avoid Liskov violation using preconditions, postconditions and invariants. If you think about conditions you’ll notice that preconditions are requirements to the user of a method, while the postconditions are the requirements to the method themselves.

The simple way to avoid breaking Liskov is to use inheritance in combination with design patterns. Template Method is the pattern that provides a useful constraint in subtyping. Errors during subtyping may occur by overriding concrete methods and forgetting calling the parent method. Another interesting subject is that the Template Method Pattern helps to avoid duplication (DRY). To avoid duplication is important to reduce the danger of messy software. Template Method Pattern is the vehicle during refactoring software to eliminate duplication which is a strong part of the TDD mantra.

With the Template Method Pattern we do not override a concrete method. Instead we implement a method as a template in the base class and let the subclass decide whether to implement the method or not. This technique helps us to avoid breaking Liskov. Therefore, the Template Method Pattern can be treated as an aid against breaking Liskov.

Simple class hierarchy implementing the Template Method Pattern:

abstract class Cooking {
   
    /**
     * No Source code duplication.
     * Let the subclasses decide the cooking strategy.
     */
    public void prepareMeal() {
       
        // buy food
        // prepare food
        cook();
        // serve food
    }
   
    protected abstract void cook();
}

class CookInOven extends Cooking {

    @Override
    protected void cook() {/* in oven */}
}

class CookOnGrill extends Cooking {

    @Override
    protected void cook() {/* on grill */}
}

class CookingBean {

    public void prepareMeal(final Cooking cooking) {
      
        cooking.prepareMeal();
    }
}


Der Rechtshinweis des Java Blog für Clean Code Developer ist bei der Verwendung und Weiterentwicklung des Quellcodes des Blogeintrages zu beachten.

Sonntag, 7. Oktober 2012

Builder Factory

A common problem is to initialize Java Collections within the builder pattern. The combination of the builder and the factory pattern solves this problem. Remember that the builder separates the construction of an object from its representation. The builder can therefore create objects which are variable initialized. The builder gives greater control over the construction process and isolates the construction code from the representation. This is easy in case of simple attribute types, but not for collections.

Collections have to be created first to store objects during the initialization process. Java inner classes support the isolation requirements of the creation process which is implemented in the builder. Isolation is one of the important principles of object oriented programming and often mentioned as a key principle of clean code. Why? The answer is simple: Isolation gives you the possibility to test your code.

The general rule is that only isolated loosely coupled objects are ready for testing. This rule is even more important whenever you start not with TDD which means you write your test code later. This is not the usual case but possible when the development team is separated from the test team. Take care and implement loosely coupled objects which are chained via Dependency Injection (DI) which is a principle integrated in the Java EE Standard as well as frameworks like Spring.

 Builder Factory Implementation:

import java.util.ArrayList;
import java.util.List;

public class BuilderFactoryBean {

    private final ItemBean itemBean;

    public BuilderFactoryBean(final Instance builderFactory) {
       
        itemBean = builderFactory.itemBean;
    }
   
    static class Instance {
       
        private final ItemBean itemBean = new ItemBean();
       
        public Instance cid(final String cid) {          
              
            itemBean.setCid(cid);
           
            return(this);
        }
       
        public Instance item(final String listItem) {          
                       
            initializeItemList();
           
            addItem(listItem);
           
            return(this);
        }

        private void initializeItemList() {
           
            if(null == itemBean.getListItems()) {
           
                final BuilderFactory<String> factory = new BuilderFactory<String>() {
   
                    @Override
                    public List<String> create() {
                       
                        return new ArrayList<String>();
                    }                   
                };
               
                itemBean.setListItems(factory.create());
            }
        }
       
        private void addItem(final String listItem) {
           
            itemBean.getListItems().add(listItem);
        }
       
        public BuilderFactoryBean build() {
           
            return(new BuilderFactoryBean(this));
        }
       
        private interface BuilderFactory<T> {
           
            public List<T> create();
        }
    }
   
    public ItemBean getItemBean() {
   
        return itemBean;
    }
}

 Item Bean:

import java.util.List;

public class ItemBean {

    private String cid;
    private List<String> listItems;

    public String getCid() {
        return cid;
    }

    public void setCid(String cid) {
        this.cid = cid;
    }

    public List<String> getListItems() {
        return listItems;
    }

    public void setListItems(List<String> listItems) {
        this.listItems = listItems;
    }

    @Override
    public String toString() {
       
        final StringBuilder strBuilder = new StringBuilder();
        strBuilder.append("cid=");
        strBuilder.append(cid);
       
        for(String listItem : listItems) {   
           
            appendItem(strBuilder, listItem);
        }
       
        return strBuilder.toString();
    }

    private void appendItem(final StringBuilder strBuilder, final String listItem) {
       
        strBuilder.append(",");
        strBuilder.append("item=");
        strBuilder.append(listItem);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((cid == null) ? 0 : cid.hashCode());
        result = prime * result
                + ((listItems == null) ? 0 : listItems.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ItemBean other = (ItemBean) obj;
        if (cid == null) {
            if (other.cid != null)
                return false;
        } else if (!cid.equals(other.cid))
            return false;
        if (listItems == null) {
            if (other.listItems != null)
                return false;
        } else if (!listItems.equals(other.listItems))
            return false;
        return true;
    }
}

 Builder Factory Test:

import org.junit.Assert;
import org.junit.Test;

public class BuilderFactoryBeanTest {

    @Test
    public void testBuilderFactory()  {
       
        final BuilderFactoryBean firstBuilderFactory = new BuilderFactoryBean.Instance().cid("cid-1").
                                                                                         item("item-1").item("item-2").build();
       
        final BuilderFactoryBean secondBuilderFactory = new BuilderFactoryBean.Instance().cid("cid-1").
                                                                                          item("item-1").item("item-2").build();
       
        Assert.assertEquals(firstBuilderFactory.getItemBean(), secondBuilderFactory.getItemBean());
    }
}



Der Rechtshinweis des Java Blog für Clean Code Developer ist bei der Verwendung und Weiterentwicklung des Quellcodes des Blogeintrages zu beachten.