Friday, 17 April 2015

MicroType

Key Challenges

Majority of application are being built or under consideration to be built on service oriented architecture which encourages decoupling of components and services. This integration project usually grows in size considering its basic feature to allow/encourages change to absorb new functionality or enhancement to existing one.

In a project the issue is about the approach related to variable creation across the code base. What can we do to minimise variable scattering and group the similar candidate variables together so that its reusability can be enhanced in line as objects?  What different we can do to streamline and create sustainable uniformity so that readability, validation, type safety and code maintainability can be enhanced?


Problem Solver

Since Java is open source and new artifacts and patterns constantly gets added or improved. So to solve one problem it is highly possible that there exist 10 different ways and workaround. To solve above stated problem the team decided to choose MicroType among other available options.


When to create & use a MicroType

One of the negatives of MicroType is the overhead of creating them for values that ultimately pass straight through the system.  If a new service has 50 values coming in on the request, then there is a cost to developing 50 new MicroType.  It is highly likely that the some of the values already have had MicroType defined, in which case it’s probably worth creating those, but equally there are probably some new values that haven’t been defined as MicroType.  Creating one for each value will be excessive if they are not used.

I would use the following rule of thumb to decide when and when not to create a MicroType

·         If one already exists then there is no harm in creating a new one ( one object extra is not going to harm anyone)
·         If a java type is used in any method in the domain service – replacing the java type with our own protects us from changes to that type
·         If a java type is used in an if condition eg
o   e.g.  int fraudScore = 72; if (fraudScore > 90) – This warrants a FraudScore MicroType with a method isOverFraudLimit
·         If you have a list or map or some other data structure that needs a ‘home’
·         If a request variable is identified as a system pass through variable, then a MicroType isn’t required


MicroType benefits

It enables easy validation, attract common behaviour, provide type safety, make code more readable and easy to maintain. Microtypes are also immutable.

Example 1- Java is a typed language, and providing a MicroType gives us a single representation of a domain/middle layer integration concept. It solves the issue of primitives-obsession.


public abstract class MicroType {

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }

    @Override
    public boolean equals(final Object that) {
        return EqualsBuilder.reflectionEquals(this, that);
    }

    @Override
    public int hashCode() {
        return HashCodeBuilder.reflectionHashCode(this);
    }

}


public class ProductAccountNumber extends MicroType {

    private final String value;

    ProductAccountNumber(final String productAccountNumber) {
        this.value = productAccountNumber;
    }

    public String getValue() {
        return value;
    }
}



Summary

No one can mistake this for anything other than a ProductAccountNumber; if this was just a String then we are then reliant on the variable name informing us of its purpose.  But this variable name could be accountNumber, which can be interpreted as product account number, bank account number, credit card account number etc.  So providing a MicroType gives a single meaning throughout the code whereas relying on variable names does not.  If we have a badly named MicroType, then a simple rename in eclipse changes all references, throughout codebase, not so the case for variable names. 



Example 2
MicroType provide a place for common behaviour.

public class Day extends MicroType {

    private final DateTime dateTime;

    Day(final DateTime dateTime) {
        this.dateTime = dateTime.withTimeAtStartOfDay();
    }

    public boolean isWeekend() {
        final int dayOfWeek = dateTime.getDayOfWeek();
        return dayOfWeek == DateTimeConstants.SATURDAY || dayOfWeek == DateTimeConstants.SUNDAY;
    }

    public DateTime getDateWithoutTime() {
        final LocalDate localDate = new LocalDate(dateTime.getMillis());
        return localDate.toDateTimeAtStartOfDay();
    }

    public Day addDays(final int days) {
        return new Day(dateTime.plusDays(days));
    }

    public Day minusDays(final int days) {
        return new Day(dateTime.minusDays(days));
    }

    public boolean isAfter(final Day day) {
        return getDateWithoutTime().isAfter(day.getDateWithoutTime());
    }

    public boolean isSame(final Day compareDay) {
        return getDateWithoutTime().equals(compareDay.getDateWithoutTime());
    }

    public boolean isBefore(final Day day) {
        return getDateWithoutTime().isBefore(day.getDateWithoutTime());
    }

    public boolean isSameOrAfter(final Day compareDay) {
        return isSame(compareDay) || isAfter(compareDay);
    }

}


Summary

The Day MicroType which contains methods such as isWeekend(), isSame(Day day).  Any other Day type logic would naturally fit onto here, rather than being all over across the codebase. 
The second point is that method now become more descriptive as rather than passing in a java.util.date (which could includes time), we are now passing in a Day reference which perfectly describes what it does “isSame(Day)”. 
Day currently wraps org.jodatime.time.Datetime.  At some point in the future we may wish to move to Java 8’s new java.time.LocalDate.  We now only need to do this in one place, rather than exposing Joda DateTime throughout the codebase, we have minimised our dependencies.


Benefits in general

·        A MicroType is in essences simply a Wrapper class similar to Boolean, or Integer wraps a Boolean or an int, but they represent concepts in our business domain.  They don’t have to extend MicroType.  But doing so create a convenience for ToString, Equals and HashCode.  A MicroType is really an object that wraps a single java object or primitive.

·         Ideally a MicroType should be created at the edges of an application, i.e. in the endpoint or in the adapters / gateway.  This minimised impacts when a variable changes type in a wsdl or when a gateway /adapter is found to represent a type differently to what we expect.


·         Ideally a domain will only ever need to use domain model objects and MicroType for all method parameters, loops and if tests.

E.g.

getAccounts(ProductAccountNumber) is better than getAccounts(String) as the MicroType version communicates better what is needed to getAccounts.  Also some American services represent ProductAccountNumber as an int where as others represent it as a String.  Not using a MicroType means that we either need to do a int to String conversion or provide an overloaded method to getAccounts.

·         It will be much easier to implement the Null object pattern if required if we first have MicroType in place.

·         Common if tests can be pushed down into the MicroType ( e.g. Day.isSame(Day))

·         Lists, Maps or other collections benefit from becoming MicroType.    By wrapping a list and implementing Iterable, we can now use our MicroType in a For loop, without exposing the fact that it is a list, meaning that if we wanted to change this to a map, or a Set at some point in the future then we can easily.  It also provides a central place to ‘manage’ that list, so if a filter for the list was required and then it would naturally fit on this object. 

Few benefits on Unit Test

As MicroType contains toString(), HashCode(), Equals() there is no needs to write unit test in order to meet 100% tests pass mark. Again this is for test purposes in order that we can use Assert.assertThat(productAccountNumber, CoreMatchers.is(expectedProductAccountNumber)).  We can now create a expectedProductAccountNumber which is a different instance, but has the same value. But Feel free to implement your own equals, hashCode, and toString on the specific MicroType as and when the methods are used, or when you believe there is a problem. This is just a convenience for testing and not an enforced doctrine

MicroType disadvantage

It is obviously a subjective things as in some area it can provide great benefits, in other it can prove to be pointless.

Reference
http://www.tutorialspoint.com/design_pattern/null_object_pattern.htm


Thank You!
Satender Kumar Mall

Twitter: satenderiiit