The string is a lie
I wanted to write something about domain driven design, most of you may have heard of it, but not realized what it is or what it means to software development. The concept is easy enough, to have an object for each object type in your domain. For instance, an address is very often represented in code as a String, but lets looks at an address more closely and find out what it really is.
Address as a domain object #
If we for a moment forget about an address being a String, what does it represent? Most would say a location and I agree, it can be translated into GPS coordinates, using tools like Google maps or similar services. It also consists of a street, a street number, a zip code and a city. Okay, so let’s flesh this out into a class.
class Address {
Location location;
StreetName streetName;
StreetNumber streetNumber;
ZipCode zipCode;
City city;
}
Okay, so now we have the makings of an address. But these objects in the Address need to be implemented as well, but I think most of you can do it yourself, but this is where domain driven design comes into play. These objects conform to rules and with rules comes validation. Now you may ask yourself why we would complicate an address into several objects and then to top it off, apply complicated rule systems to these objects. The reason is simple. Domain driven design helps us to enforce that data put into these objects conform to rules, it also protects us to a certain degree from injections, if we enforce the rules and perform correct validation of the data.
The rules #
Okay, let’s start with the City object. Doing a quick Google search reveals that the longest known location that might qualify as a city object is 85 characters long. Just to be sure, we can safely assume that city names are less than a hundred characters long (at least for a few years, until someone wants to break the current Guinness record). We also know that city names start with a capital letter and that the remaining 99 letters should be lowercase. This is something we can create a rule for. Lets flesh it out.
class City {
private static final String RULE = "^[A-Z][a-z]{1,99}$";
String cityName;
City(String cityName) {
if (Pattern.compile(RULE).matcher(cityName).matches()) {
this.cityName = cityName;
} else {
throw new CityNameValidationException();
}
}
}
Now, this is the beginning of a working domain driven design. It allows us to perform input validation on any incoming data, it also helps us to flesh out a database schema and to enforce a proper domain object throughout our solution.
Conclusion #
Most people that see this design the first time complain a lot about there being a lot of objects to implement and it will create a lot of useless code. My answer to this would be DRY (Don’t Repeat Yourself). The rules of a city name does not change over night, take your domain objects, put them into a separate project and use that as a dependency in all your projects. Extend that dependency every time you need a new domain object and you will soon find that it will cover almost every conceivable scenario.
Beyond this, it will give you some protection from injections, provided you actually do data validation in your backend domain objects and it will also make your domain model more understandable and concise.