Overview:
This article looks at Tiny Types, a pattern for writing code in an expressive manner.
Every developer should aim to write highly maintainable piece of software. This not only promotes minimal effort to maintain the software but also cost effective in the long run. One such way of writing a maintainable software is to make your code (including your tests) highly readable. Writing code in an expressive manner(using domain concepts that your software is targeted towards) greatly improves the readability of the code.
Tiny Types, is one such way that allows to write highly expressive code. This is a pattern used to encapsulate built-in types such as String, Integer, Big Decimal etc in a domain specific concept. I have used this pattern in several projects to great-effect that promotes Domain Driven Design concepts.
Snippet 1: Writing using built-in types
public class Student {
public final String id;
public final String name;
public Student(String id, String name) {
this.id = id;
this.name = name;
}
. . .
}
The above example looks fine, however it doesn’t guarantee from us interchanging the two parameters,
Student s1 = new Student(“SID001”, “Harry”);
// syntactically correct, however, this will cause system failure in runtime.
Student s2 = new Student(“Sam”, “SID002”);
which would lead to bugs in the system that are hard to discover and waste precious time and money on finding and fixing them.
Snippet 2: Rewriting the above as follows
public class Id {
public final String id;
public Id(String id) {
this.id = id;
}
. . .
}
public class Name {
public final String name;
public Id(String name) {
this.name = name;
}
. . .
}
public class Student {
public final Id id;
public final Name name;
public Student(Id id, Name name) {
this.id = id;
this.name = name;
}
. . .
}
Where, Id and Name are separate classes to represent student id and name respectively. Now, you have THREE classes altogether instead of one single Student class. That means you have to write extra bit of boiler template code, but it should be fairly easy with the IDE support available, today.
With this approach several advantages are immediately visible.
Improved Readability - Now, the definition of the classes becomes very expressive and concepts around the system gets more clear.
Segregation of Responsibility - All the responsibility specific to a given type should reside in its class. With the new design, the responsibilities are well-defined and self-contained in the type definition.
e.i. The validation logic related to a name should be placed in the Name class itself. Otherwise, as per code-snippet-1, we would have done the validation in the student class, which isn’t really relevant there.
Compile-time Error Detection - Since Java is statically typed, with the current design, we will not be able to interchange an id with a name, whereas, in the previous design it was allowed.
Student s1 = new Student(new Id(“SID001”), new Name(“Harry”));
// Not allowed anymore, this will cause compilation error.
Student s2 = new Student(new Name(“Sam”), new Id(“SID002”));
Thread-safe - We can make the tiny types immutable, thus they can be used in a concurrent environment. Also, it will ensure that no other parts of the system will be able to modify the state of these objects.
Automated Tool Usage - With the new design, code refactoring and finding usage of the references of these types becomes much more simpler and provides far better useful results.
Finding the references on the “Name” class results more helpful results than performing the same operation on a String typed field.
On the contrary, many would argue that introducing this pattern to a system would end up in creating a lot of objects has a result of encapsulating built-in types and hence, a high memory usage and makes the system slow. Actually, these tiny type objects are short-lived and If you consider how the Garbage Collector works, it actually tries to preserve the objects (long lived) that are referenced by the system and not otherwise. Thus, creating short-lived tiny types will not affect the Garbage Collector. In fact, the Garbage Collector will have less work because it simply doesn’t care about short-lived objects.
In summary, based on my personal experience, the adoption of Tiny Types immensely improves the readability, quality and the maintainability of a piece of software, and the benefits of this pattern overweighs the initial effort required to adapt.
No comments:
Post a Comment