An interesting predicament that all applications will face is, how do you validate incoming data, and how do you communicate errors back to the user interface?
As we’ve seen over the last couple of weeks, we can encapsulate Domain related rules and logic inside of the Entities, Value Objects and Specifications of our application.
These Domain Objects protect against inputs and operations that do not meet the business rules of the application. By encapsulating the business rules inside of the object, the consumer of the object does not need to be concerned with how the rule is enforced.
But in the grand scheme of an application, there is going to be lots of incoming data. Should you rely on the logic of your Domain code to act as the single source of truth?
In today’s article we’re going to be looking at how I prefer to deal with incoming data, and how to communicate problems back to the user.
The problem of incoming data
Nearly all applications will have incoming data in one form or another. However the big problem with accepting data from the outside world is, you simply can’t trust it.
No matter how slick or intuitive your user interface is, users will always make mistakes when entering data. This could be as simple as an invalid email address or perhaps a missing required field.
Your application will also likely have rules around the data it can accept. For example, if a username is already taken, you wouldn’t want another user to be able to register with that username too.
And finally, all applications will have malicious users trying to circumvent the rules of an application. It’s very important that you do everything you can to shut down any vulnerabilities that your application might leave exposed when accepting incoming data.
The Domain layer as the single source of truth
Over the past couple of weeks we’ve looked at encapsulating the business rules of the application using Domain Objects.
For example, we created Value Objects for
Username that would ensure the input matched our criteria for being valid (Encapsulating your application’s business rules).
We also created Specification objects that could select objects from the database to check for uniqueness. This means we can ensure that a user’s chosen username and email have not already been registered (Implementing The Specification Pattern).
Domain Driven Design is all about modelling the business rules of the application in code. Whilst this particular application is fairly simple, we now have a rich Domain layer that will enforce the rules of the application.
However, should the Domain layer act as a single source of truth? When a request comes in from the outside world, should we rely on the
Whilst everyone knows you shouldn’t repeat yourself, I think there is a time and place to “violate” this rule. Instead of having a single source of truth when it comes to validation, I think you need multiple layers of validation.
Multiple layers of validation
When building a web application, you usually have a set of basic rules for the requirements of incoming data. For example, perhaps you require the user to enter their first name, last name and a valid email address.
Typically when building out the PHP side of the application you will enforce these rules in one of many possible places. In Cribbb I’m enforcing the rules using Value Objects, but you might instead be running your validation in the model.
If you follow the “rules” of good programming, you will know that you shouldn’t repeat the same logic. For example, validating data in the controller tends to lead to duplicate code because you end up needing that same validation logic else where in your application. Most developers are pretty emphatic about not repeating this type of logic.
Typically copying and pasting code is usually a bad thing, but I think when code is doing two very different jobs, it’s fine to repeat the same logic.
Therefore, I believe there should be multiple layers of validation in your application to deal with the different problems that can arise.
Duplicating validation rules is usually fine because as long as your Domain logic is correct your application won’t start allowing invalid data. Discrepancies between the additional higher layers of validation can usually be picked up through Quality Assurance testing.
Your Domain rules should therefore be the final guard against invalid data, but certainly not the only one.
The different layers of validation
I think the vast majority of web application will have fairly similar validation requirements and so the following validation layers are probably applicable to most projects.
Client side validation
For example, first names and last names should probably not contain numbers or symbols, and email addresses follow a fairly predictable pattern.
Instead of reinventing the wheel, a good choice for this type of validation is jQuery Validation.
Application Service requests
When you need to check input data against the business rules of your application there is no avoiding making a server request. However allowing the user to submit the form before telling them that their chosen username has already been taken is really annoying.
Instead you should be able to send an Ajax HTTP request to the server to query against the database.
This can be implemented by writing an Application Service that exposes an interface to accept these types of requests and return the appropriate response. This means the user can be notified almost instantly if they have entered data that violates the application’s business rules.
These Application Services can be really simple because all they have to do is receive an HTTP request and then return a response in JSON.
Framework validation library
When the user submits the form, the request will typically be routed to a Controller who’s job it is to route the request through the application to the correct destination.
A lot of application framework’s ship with validation libraries. Laravel for example has an excellent Validation Library that allows you to validate data in a number of useful ways.
The depth of validation you implement at this level is usually specific to the type of request that is being made. In a lot of instances you can simple check for the correct data types to make sure the required fields have been completed and the data looks like it’s in the correct format. If these validation checks fail we can very easily abort the HTTP request and redirect back to the form.
Controllers also typically handle requests that don’t match the shape of the Domain layer. For example, if you were accepting a new order request in an ecommerce application, you are probably mixing together
Product validation rules. This means your Controller validation can act as a light layer of protection against invalid data across multiple related components of your application.
Having a layer of validation in the controller serves the purpose of handling any obvious errors before the request makes it into your application.
Finally we have the Domain validation that is encapsulated in Entities, Value Objects, Specification as well as any other Domain Object that enforce the business rules of the application.
Domain Objects can signal a problem in one of two ways. Either returning
false from the method, or by throwing an
Exception that should be caught at a higher level.
As I covered in When should you use an Exception?, I believe Exceptions should only be thrown in exceptional circumstances. If
false is an acceptable response from a method, avoiding using Exceptions in these instances is usually the right choice.
So for example, if we had a
UserRegistrationService, we might return
null if the user registration process failed. We could then expose an
errors() method that would pass the errors back up to the User Interface.
On the other hand, a lot of the time it does make sense to throw Exceptions if something goes wrong. You could argue that this makes more sense in the Domain layer because this is our last form of defence against the outside world.
The Domain layer could throw a Domain Exception if one of the business rules had not been satisfied. This Exception could then be caught in the Controller layer in order to return the feedback to the user.
If you have a pretty robust layer of validation before the Domain layer you might instead want these Exceptions to bubble all the way back to the surface to halt the application’s processing. The Domain layer should protect against malicious attacks and so if you believe that the request must be malicious because it made it’s way through your additional layers of validation, it might be better to just bail.
Validation is something that virtually all web applications will require in one form or another. User’s will always make mistakes when inputting data, and there will always be a minority of malicious users who will attempt to break or circumvent your application’s defence in order to cause mischief.
I think there are many mantras in programming that get taken to the extreme. Don’t Repeat Yourself is an important rule, but it’s not something you need to be dogmatic about.
Copying and pasting code is usually always a bad thing, but repeating logic can actually make your code a lot easier to work with and understand.
Your Domain code should sit at the heart of your application and protect the valuable business rules that make your application unique. However, your Domain code is not responsible for providing every type of validation check throughout your entire application.
Your Domain Entities should not be designed to work with a framework’s form validation library and they should definitely not assume the responsibility of every relevant validation check.
Instead, free yourself of the burden of Don’t Repeat Yourself. Sometimes repeating yourself is exactly the right thing to do.
To view a full listing of the tutorials in this series, click here.