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