Note: this post is a work-in-progress

The world of software development is moving very fast, so to be competitive and write good/clear code developers need to update their skills continuosly. While I was looking for something new to improve my code, I have found this talk by Edson Yanaga from JavaDay 2016. A 50-minutes long talk where Yanaga exposes several techniques to improve code readability and quality in a live session. I've found a lot of usefull tips in this talk, I have written ten of them down in this blog hoping it could be useful for someone else.

TALK on Youtube

SAMPLE PROJECT: You can find the source code of the sample project here on my github repository

Domain Driven Design

The talk is mainly focused on the Domain-Driven Design with Java 8, JPA 2.1 and some addtional libraries like Google's Guava.

Domain Driven Design is a vision and approach for dealing with highly complex domains that is based on making the domain itself the main focus of the project, and maintaining a software model that reflects a deep understanding of the domain. The vision was brought to the world by Eric Evans in his book "Domain Driven Design".

For quick introduction to the theory, here is a free ebook "Domain Driven Design Quickly" by InfoQ.com ( download ebook ).

The talk use mainly these concepts from Domain Driven Design:

  • Entities
  • Value objects
  • Aggregates

Context

The contenxt of the project will be a classic enterprise application, where the user needs to make orders of some products. The code will use a set of patterns to have a solid domain model with a built-in validation.

Tip 1: Static Factory Methods instead of constructors

Directly from Effective Java by Joshua Block (some notes here): use static factory methods instead of constructors. There are several reasons to do it:

  1. Polymorphism could be applied to the factory method
  2. Business logic and data validation can be implemented inside the factory method

Code

//new code - covariance supported
OrderItem shoes = OrderItem.of("shoes", 3, cost );

Tip 2: Defensive programming

Always use defensive programming inside methods ( helpers provided by Guava's Preconditions ), to make the software behave in a predictable manner despite unexpected input (i.e. Null values). A nice post could be find here.

Code

public void addToListOfDesires(OrderItem item){
    if ( item!=null && !listOfDesires.contains(item) ){
        listOfDesires.add(item);
    }
    ...
}

Tip 3: Implement Equals and HashCode

Again from Effective Java: implement equals() and hascode(). This becomes crucial when using Java collections (i.e. .contains() like methods ).

Code See sample of tip#2

Tip 4: Implement toString() for logging puporse

This is a good point, usually toString() method is more used for logging purpose than displaying purpose.

Code

@Override
public String toString() {
    return MoreObjects
        .toStringHelper(this)
        .add("value", value)
        .toString();
}

Tip 5: Use the Formattable interface

For displaying purpose Java has the Formattable interface which is used for I18N too. So implmenting formattable interface is a good idea to have simple I18N.

Tip 6: Use ColumnConverter for single Value Objects

Simple Value Objects does not need to become separated/unconfortable tables on the database, using ColumnConverter feature, a simple Value Object can be mapped easily to a column in the same table of Value Object's owner.

Code

ColumnConverter.java

Tip 7: Use @Embeddable and @ElementCollection for list of Value Objects

When a list of Value Objects are used it can be mapped as @Embeddable and @ElementCollection without using the @OneToMany/@ManyToOne relations.

Pro:

  • no need of explicit id and inverse mapping. More details here.
  • Cascade managed automatically

Cons:

  • An @Embedded element cannot exist without its owner

Tip 8: Use Immutability as much as possibile for handling thread safety and concurrency issues

An object is considered immutable if its state cannot change after it is constructed. Maximum reliance on immutable objects is widely accepted as a strategy for creating simple, reliable code. Immutable objects are particularly useful in concurrent applications. Since they cannot change state, they cannot be corrupted by thread interference or observed in an inconsistent state. Oracle's essential tutorial

Code

public List getItemList(){
    return ImmutableList.copyOf(items);
}

Tip 9: Use a wrapper for managing list of Objects with Domain's rules ( ForwardingList )

There are several reason to use a wrapping class

  1. Incapsulation and data hiding
  2. Immutability and control over data
  3. Easy to read ( i.e. Total elements of the order: Order.getItems().getAmount() )
  4. Use domain's rules to check consistency of the data

i.e.:

In the sample project an Order have several items. We don't want to expose Order's item as a List and allow other developer to put unvalidated data in the list. So we can create an OrderItems class which has only the operations that we allow to have, also we can add some business logic and validation in the class to mantains our data consistent.

Code Look at the OrderItems class

Tip 10: Use the Java 8's Function

In the sample code each Order has some OrderItem. In order not to expose the rappresentation on how items are rappresented, we can put a global manipulation method in OrderItems class. But if we have several custom operation on the item it will make OrderItems class very long and full of complicated methods. To reduce the Order class complexity a method apply(function) can be created in the Order class using the Java 8's Function class.

This could sound like a complication in a first place, but it will the code cleaner and understandable when get used to it.

Code

//apply discount to each item of the order
order.apply( OrderItemOperations.DISCOUNT );

Take a look to these classes:

Conclusion

This talk is very useful and full of approches and tecniques to learn. Topics found:

  • Use Effective Java tips in practice with Domain Driven Design
  • S.O.L.I.D. principles
  • Usage of Java8's Function
  • Tips on Logging/Display
  • Tips on what expose and how to other developers
  • etc.

Take a look at the test class to see how the code became readable and easy to understand applying these rules

I hope this document could be usefull to someone else someday. Contact me if you have any suggestion!

Feedbacks

Awesome feedback directly from Yanaga! Yanaga Feedback

Have a nice day :)

Next Post Previous Post