Data correctness and the ability to enforce business rules of a given domain, are one of those aspects of software development that are common to practically any project. Since it’s difficult to imagine any non-hello-world applications that wouldn’t require some sort of validation, solving this problem area is vital to overall project success.

For sure, such a core concept is bound to affect overall architecture, and any approach taken should ensure that only valid data is used to perform relevant business operations throughout the code. As such, the chosen design should integrate seamlessly with business logic and provide a reasonable level of protection. In addition, from a development, maintenance and user experience standpoint, it is often required for software to report whenever validation errors occur.

Together with Zbigniew Artemiuk and Przemysław Rafalski, we’ve played with this topic a bit, and in the resulting article, we’d like to present one way of implementing validation for a simple application kept in the spirit of domain-driven-design.

Note:

The presented code base is referring only to classes relevant for this discussion. The complete project is available here.

Domain and application:

Our little project’s main feature is to register users by a given email address and password. The relevant basic model representing our domain may consist of an entity representing the user:

Along with value objects encompassing concepts of email and password:

We’d also like to store successfully registered users in a repository, whose interface would initially look like this:

The last important feature would be the ability to find users by their email address value. For this purpose, let’s introduce yet another class:

From our application standpoint, we’ll be exposing two REST endpoints, respectively for accepting user registration requests and for returning the email address of the user registered under a given id.

Validations

The requirements on data correctness are pretty obvious — the application can only accept registration requests having a well-formed email address specified. Also, since it is supposed to uniquely identify a given user, we cannot allow two users to share it. To protect our beloved users from brute force attacks on their passwords, we’d like them to use only strong ones, as per the application’s defined policy — it mustn’t be shorter than 5 characters in length.

Other than protecting our business rules, we’d like to return information of validation failures to the user, should any occur when processing the registration request.

Before we address the latter requirements, let’s first implement actual validation logic as would probably be prioritized in any project.

Since we’d like to keep our validation logic close to the domain objects it relates to, let’s start our implementation using constructors of respective building blocks, beginning with our value objects — Password and Email classes.

Password validation

Validating the password’s strength does not require any additional contextual data, other than the value passed in the registration request. Our implementation can then be trivial and may be encompassed within a simple PasswordValidator class throwing PasswordTooWeakException in case of failure, as presented below:

Usage of this class in the constructor seems pretty obvious:

Disregarding issues with tight coupling and discussion on whether or not the constructor is best suited to throw exceptions, this most simple approach ensures that no instance of Password would ever get created for a value not complying with the application’s security standards.

Email validation

Considering the requirements around email validation, one thing that pops up is the inability to ensure its uniqueness within just its own scope, as it can only be told against a group of emails currently present in the system. What we’re able to do on this level, however, is to ensure that the specified address value is in fact well-formed. We can apply a similar approach as for Password :

And the usage in the Email class constructor:

This way, we have partially addressed our requirements towards email. The outstanding item, being its uniqueness, actually reflects a restriction more related to the containing User entity, than to the email address itself.

User validation

As we need to check if a given email address has not already been registered to any existing user, it’s clear that our validation logic will require some access to the repository. Putting such dependency in the User entity class and performing repository-based validation in the constructor does not seem like a good idea though — just think about all the potential infrastructural errors that might happen there, and the resulting necessity of handling them in the constructor. Thankfully, we can use one of the simplest creational patterns to mitigate it — the factory. At its core, this pattern is used when creating complex objects, taking part in the dependencies management etc., Furthermore, in DDD it’s often also responsible for performing validations. This sounds like a perfect match for our scenario!

Once we have that in place, we can implement the necessary validation logic within the EmailUniquenessValidator class:

Our last pending change would be to add a new repository method. For the sake of simplicity, let’s just limit the changes to the interface, as the actual implementation is of no concern to our discussion.

Collecting validation errors

At this point, our application should pass any validation-related tests we could think of within the range of set requirements. That’s good! Unfortunately, however, we haven’t yet addressed the necessity of collecting and presenting situations of dealing with user data non-conforming to our domain restrictions.

Since our validator classes are throwing exceptions whenever our rules are compromised, the simple and somewhat naive approach would be to catch and translate these exceptions into user-friendly representations. Such logic would be placed in the controller, and since our validation exceptions already extend to the ValidationException class representing the whole validation errors exception group, we’d wrap that up with a dedicated exception handler to do the translation job and voilà — what a nice solution we have! There’s one drawback, however — with the current implementation, we’d only be able to catch a single, first-occurring error, which is not the best experience we could offer our dear users, is it? Separate try/catch clauses for each object creation? This would solve our problem, but let’s do better.

One idea would be to use a variation of the visitor behavioral pattern, allowing us to externalize the decision on what to do with the exception object, produced by a validator. Let’s explore how that might look, going in the bottom-up direction this time — from validators up to the controller.

Handling validation exceptions

Instead of explicitly throwing an exception, we’d like to delegate this decision to some external handler. One way to do that is for the validate method to accept an additional parameter.

As for the responsibility of our new class, at its core, we simply want it to be able to accept validation exceptions. Let’s then create the following ValidationExceptionHandler interface expressing just that:

Our current requirements reveal two required implementations — one that will serve the purpose of collecting errors:

And the other one, which will immediately re-throw the first added exception, as was our initial approach:

Now moving to validators, due to its simplicity, take the PasswordValidator for starters. Usage of our newly defined validation exception handler would look as in the following snippet:

With this implementation, our ValidationExceptionHandler is responsible for what happens to the produced error. Let’s bubble the new method argument one level higher, to the Password class.

Here it becomes obvious that due to our change, we can no longer ensure that any instantiated Password object would be valid, as it depends on the actual implementation of the ValidationExceptionHandler used. We don’t want that. Thankfully, to provide backward compatible behavior, we’ve implemented a ThrowingValidationExceptionHandler class, that would fit just right as a default handler. The validation operation, for non-construction-related scenarios, needs to be moved to a separate method, accepting the handler as an argument. As a matter of stylistic preference, let’s add static methods for construction and validation:

As implementing this approach for the Email and User (well, along with UserFactory to be precise) would be almost identical, let’s skip it for brevity.

The controller

From the perspective of our logic flow in the user registration endpoint, we’d first like to ensure that the given data could be used, before we attempt to create any of our domain objects. Let’s introduce this approach:

Here we can clearly see the usage of our newly added test methods, along with collecting the exception handler. This answers the requirement of gathering all the occurring validation errors, and allowing us to create domain objects only if no errors actually occurred.

The resulting separation between performing validation for the sake of reporting and actual object instantiation, has its drawbacks, however.

The first of these is an interesting scenario, when the validation performed within the test method and consecutively within the constructor report different results. This might happen with the email uniqueness check, when during the initial test, our storage state did not contain the given address, however in construction time, its state has already changed and validation no longer passes. Transactions with pessimistic locking, though they might address this, are not always eligible. The good news though, is that such situations can be considered rare enough, and not really all that dangerous, as the worst thing that might happen is that the object won’t get created and the ValidationException typed exception would need to be handled. The other issue is executing the validation twice, which might impose a potentially significant performance hit. In our case, the PasswordValidator

and EmailValidator validations are clearly negligible in regards to the computations required. Rather, it’s the EmailUniquenesValidator that might cause us trouble due to its access to an external resource, possibly a remote DB with non-optimal connection characteristics.

Summary

As we’ve seen, implementing domain validation rules close to our domain objects is not all that troublesome, and with usage of factory and visitor patterns, one might even say it’s trivial. Moreover, keeping these two aspects nearby gives a boost to understanding the domain rules. On the usage side, pushing validation logic to the lowest possible level ensures that only valid domain objects get created, saving developers from a defensive approach. It also helps in project maintenance, preventing situations where validation logic spreads throughout several distinct layers of the application. Despite the drawbacks of performing checks multiple times or possibility of optimistic locking issues, we believe this approach allows us to draw a clear demarcation line between business logic and validation code, doing so in a neat and elegant way. We hope you’ll find it useful in your projects!