Micro Types!
There is something interesting I often notice in software engineering and software architecture. At least is something that I find interesting. I tend to rediscover a fondness for solutions I have used before. One of these nuggets of interest is Micro Types.
So what is a Micro Type? A Micro Type simply encapsulates a primitive or a String. Say what? You expect me to wrap a simple number or a string of characters in a class? Have you gone mad?
Let's look at an example! Consider the customer administration of a company. Inside this administration there are different types of identifiers to identify a customer. For example a customer identifier or a contract identifier.
public Customer retrieveCustomerById(String customerId) {
// Logic to determine if this is really a customer identifier
}
public Customer retrieveCustomerByContractId(String contractId) {
// Logic to determine if this is really a contract identifier
}
Now if we have more and more of these types of identifiers this could get out of hand quite quickly. Because they are Strings we could easily mix them up. And what about validation? Where should that take place? This might be all over the place or we might forget to validate at some point.
What we learn with OO and especially DDD that is good to have logic inside our domain. And who would know best what it means to be a customer identifier? The identifier itself!
Now let's look at this change.
class ContractIdentifier {
private final String identifier;
public ContractIdentifier(String contractId) {
/**
Logic to determine if this is really a contract identifier or
throw an exception (InvalidIdentifierException)
*/
this.identifier = contractId;
}
public getIdentifier() {
return this.identifier;
}
}
class CustomerIdentifier {
private final String identifier;
public CustomerIdentifier(String customerId) {
/**
Logic to determine if this is really a customer identifier or
throw an exception (InvalidIdentifierException)
*/
this.identifier = contractId;
}
public getIdentifier() {
return this.identifier;
}
}
}
public Customer retrieveCustomer(ContractIdentifier contractId) {}
public Customer retrieveCustomer(CustomerIdentifier customerId) {}
Now I know this is more code, but consider that we are probably using these identifiers all over the place. Also constantly validating the String is very prone to mistakes if ever the validation needs to be changed. We now have the validation encapsulated inside the type itself.
To see more of the benefit here is an extra example with Spring MVC.
@GetMapping("{contractId}")
public Customer getCustomerByContract(@PathVariable("contractId")
ContractIdentifier contractId) {
// Logic to call a service that can handle the work for us
}
The interesting thing to note here is that you get validation of the provided path variable for free by using the micro type. Now you would need to write a bit of code to get the conversion into our type done, however that could done very easily.
Conclusion
I have shown a few benefits of using micro types. I think this improves maintainability significantly, because code is easier to read and easier to reason about. No longer do you need to consider if a String is representing X or representing Y. By encapsulating even the smallest pieces into a class we get a lot of benefits all over the place.
Now I do not recommend doing this for every single field or variable, but especially those that are used a lot and have significant meaning within your application.