Best Practices for Business Logic Validation
Validation is a critical aspect of any web application, especially in true web applications that offer advanced functionality for sophisticated users – people who use the application continuously, all day.
Validation in such applications is often very complicated: validation rules may involve multiple related entities and complex conditional logic – it’s not just “integer greater than zero”.
At Isomorphic, we are frequently asked to rescue projects that are failing (usually because they didn’t use our technology and services up front!). Very often, when we encounter performance problems, it’s related, directly or indirectly, to validation.
And yet, in most projects, when developers try to anticipate possible performance problems, they don’t consider validation at all.
This is a big mistake! And a very common one.
In this article, we’ll outline the best practices that we apply when rescuing projects, or when creating new applications.
While these best practices are essentially “baked in” to our technology – SmartClient – they can be applied with whatever technology you happen to be using.
Let’s get started.
1. Validation is a cross-cutting concern
Validation requires coordinated efforts from both client and server teams – it is a “cross-cutting” concern. The server team needs to ensure that the validation rules are enforced, while the client team needs to ensure that unnecessary server requests are avoided by performing validation on the client-side whenever possible. Proper validation is crucial for performance, responsiveness, and data accuracy.
Validation is typically not given the attention it deserves, with many developers only implementing it on the server. This often happens when the client-side team is separate, working with a different technology or programming language. This failure to prioritize client-side validations can lead to slow response times, frustration from users, and increased server load.
Before we even talk about technical approaches, we would recommend that there is a single person on your team who is the lead on validation – the “validation czar”. Done properly, validation is a distinct subsystem, with both client- and server-side components, that is reused across many screens. But this won’t happen “organically” – if you don’t make a specific effort to standardize your validation approach, developers will just do whatever they need to do to complete the current screen.
A “validation czar” gives you at least the possibility of creating consistent, reusable validation code – which is also key to performance.
2. Single-source validation
Single-source validation means that you create a single, declarative format for validation rules, and this format is used by both your client- and server-side code.
The format isn’t really important (SmartClient allows both XML and JSON) – the key is that you have a validation engine on both the client side and the server side, and both engines read this shared format.
Imagine having a single location for all your validation rules, accessible to both the client and server. That’s exactly what single-source validation offers. With this technique, you declare your validation rules in a format that is easily accessible to both client and server logic, so the same rule is executed automatically in both contexts. No more duplication of effort, no more inconsistencies in validation, and no more frustration.
Further, single-source validation helps you achieve optimal performance and responsiveness, because, when you declare a validation rule, the client-side system enforces it too – there is no longer an extra effort required to implement client-side validation.
Thus, by eliminating the need for multiple server requests, your application will run smoother, faster, and more efficiently.
With all your validation rules in one central location, it’s easy to update and maintain them. And with effortless coordination between client and server teams, you can ensure that your validation rules are always in sync and up-to-date.
3. Rich declarative validation library
Once you’ve adopted single-source validation, you want your library of declarative validators to be as comprehensive as possible.
Having a single source for basic validators like “number is between 1 and 5” is great, but ideally, you can declare much more complicated things, such as “this field is required if some other field has a specific value”.
The more you can declare complex validation rules, the more often invalid requests will be caught in the browser, the more unnecessary server requests will be avoided, and the more responsive and scalable your application will be!
A key technique here is criteria-based validation. This means that you can declare both when a validator is active and also what is to be validated. imagine you want to enforce the rule that the ship date cannot be changed if the Order’s status is already shipped. With SmartClient, you can easily express this with a simple line of code, like so:
<field name="quantity"> <editWhen fieldName="Order.status" operator="notEquals" value="Shipped"/>
This isn’t just a performance advantage – it’s also a major reduction in coding effort. No more duplicated validation logic across different screens. With this approach, you’ll be able to create complex validation rules quickly and easily, leaving you more time to focus on other important aspects of your web application.
4. Split validation
Criteria-based validation has a lot of power, but still, there are many validation rules that can’t be expressed in declarative criteria.
This is where the split validation technique comes in: declare part of the validation rule using criteria, then the rest with custom code.
Your client/server validation engine will be able to enforce the criteria-based validation rule, which also means no unnecessary server requests.
Then, you express the rest of the rule with custom server logic.
Split validation is an optimization technique that not only improves the performance of your application, but also helps developers be more productive. By enforcing validation rules on the client-side, it eliminates the need for unnecessary server requests. On the server-side, the complete rule is applied to ensure consistency and correctness, giving developers peace of mind that their validation is airtight.
5. Cache-aware validators
There are a lot of validation rules that need to check related entities (such as the Order.status check above) or need to consult the entire data set (like an “is unique” validator, for example).
From a performance perspective, these are some of the most expensive validation rules. When enforced on the server, such rules may require multiple database queries to correctly enforce.
The ideal validation engine avoids unnecessary server requests whenever it can – by being cache aware.
Cache-aware validators know about client-side caches and can inspect them in order to potentially avoid expensive server requests. Although this technique applies to many different validation scenarios, the easiest to understand is the common “is unique” validator, which checks for collisions when users are naming things like projects, estimates, articles or other entities that require unique names. It’s also used for data consistency purposes, to detect duplicate customers, suppliers, partners, and so on.
A cache-aware “is unique” validator checks the data that is already loaded for collisions first, avoiding an unnecessary request to the server to check uniqueness in cases where a collision can be detected in the browser.
To illustrate the importance of this, in one large banking customer of ours, several years ago, database performance profiling revealed that 3 different queries related to uniqueness were actually a huge proportion of DB load – more than 30%.
We realized there was an opportunity to make the validator smarter by being cache-aware, but in a very specific way: when you are dealing with large datasets that are only partially loaded, you can’t do an “is unique” check purely in the browser, because there might be a collision in data that isn’t loaded. However, you can check whether there is a collision in your local cache, and signal failure if there is such a collision.
Further, if the local cache happens to be both entirely complete and quite fresh, you can allow the “is unique” validator to pass client-side, which allows other client-side validations to be done, which may in turn prevent an unnecessary server trip.
Seemingly simple, but extremely powerful. In the particular app we were looking at, we found that this optimization produced a ~70% reduction in server-side “is unique” checks, which was a huge boost to overall performance.
And the best part? We rolled this improvement into SmartClient as a default behavior for the built-in “isUnique” validator, and now all of our customers get that benefit.
We’ve been refining SmartClient’s validation engine along these lines for several years now. Basically, if it’s possible to perform validation given the data that is loaded, SmartClient does it. It’s a subtle but enormous web application optimization.
6. Standard validation protocol
Another best practice for implementing validation in web applications is to use a standard client-server validation protocol that can handle any type of object.
You want to be able to make a request saying: “if I change these fields on these objects, is that valid? What are the errors?”
Many (if not most!) projects end up implementing separate, per-entity validation error handling, with a huge amount of duplicated code across different screens.
A standardized validation protocol avoids this problem, and also makes it straightforward to implement a true validation engine that intelligently uses the server only when it needs to.
This is all built-in to SmartClient. If you are using some other technology, feel free to copy our protocol and our approach. However, this is another place where we would recommend a “validation czar”, to coordinate efforts across your client- and server-side developers.
Building a coordinated business logic validation system
I hope I have made it clear that there is tremendous value in a client/server validation engine, and that it should have all of the traits explained above, whether that engine is based on SmartClient or not.
Further, this concept – a shared client/server engine, with declarative configuration – isn’t limited to just validation. Other behaviors, such as whether & when specific fields are editable for users with specific roles, similarly require coordinated client & server behavior: what you ideally want is that a single declaration causes the server to reject attempted edits, and the UI to show a non-editable field. SmartClient implements exactly this.
There is a pernicious industry assumption that you can pick client and server technologies and teams separately and it will just “work out”. This is simply not true. Validation is one of several “cross-cutting” concerns where you need deep coordination between client and server teams, as well as a set of components that span from browser to server.
Conclusion
Whether you are using SmartClient or not, feel free to contact us if you need help designing a validation subsystem that is performant & responsive. We have become very proficient at minimally modifying existing systems to capture the performance benefits discussed in this article.
However, if you want to build an application that really, really performs, please start with us, as that’s the easiest way – with SmartClient, performance is built-in.
Please contact us, or for more performance insights, or check out our article on other key considerations for optimizing web applications.