Designing for Validation

by Kevin Garwood

Limiting the scope of development efforts

Our first step in designing the RIF for validation is to limit what parts of the code base that will support validation activities. In the three-layer architecture, validation will be divided between the business concept layer and the data storage layer. Although validation code could be included in the presentation layer, there are two reasons for not placing any emphasis of validation in this layer:

Given that we anticipate future development of front end applications to be volatile, we believe it is best to conserve as much business logic for validation within the business concept and data storage layers.

Validation-1 : Assume the client applications will do no validation. Validation code will be distributed between the business concept and data storage layers of the architecture.

Now that we have limited our concerns about validation to the business concept and data storage layers, we now look for other ways to economise our efforts. In the general design of the architecture, we decided to limit paths of execution wherever possible. Two general design decisions help make it easy to know where validation efforts should be focused:

General Design-4 : Wherever possible, limit the paths of execution that are likely to occur.
General Design-7 : Encapsulate business concept and data storage layers of the architecture through service APIs. Do not allow clients to know which class is implementing the service interfaces.

The emphasis for validation should focus on validating data passed by the client:

Validation-2 : Limit validation support to execution paths that support service API methods. Specifically, focus validation efforts on validating values the client application passes to methods of service APIs.

Designing the business classes to accommodate validation checks

The next step for supporting validation is to make it easy for the client applications to rely on the middleware to do validation. In most client applications, form field values will be typically be Strings. Therefore, if the middleware is meant to do as much validation as possible, it should accept field values as Strings. It is best that the business classes use mostly String fields so that the client can easily copy form fields to data fields.
Validation-3 : By default, the fields in business classes should be of type String.

Ensuring parameter values remain the same before, during and after validation checks

In order to eliminate the prospect that parameter values passed by a client could change during the execution of a method code block, we make local copies of every mutable parameter value of every service method. This measure ensures that once parameter values have been validated, they remain valid until the method finishes. (See also Concurrency).

Concurrency-9 : Perform a deep-copy of any mutable object that is passed to a service method by a client application. This action will prevent the client from altering parameter values while they are being processed by the middleware.

Identifying and ordering validation checks

Once the parameter values have been safe-copied, we can be assured that values will remain the same when they are being validated. The next step is to identify and prioritise what validation checks are applied to the parameter values of service methods. The order should ensure that a service request uses the least amount of the system resources. If an attempt to call a service method is going to fail, it should fail as quickly as possible and minimise how much work it makes the database do.

Failing fast can be more important in some scenarios than others. For example, as soon as a malicious code attack is detected in any field of any parameter object, the method should fail as fast as possible. Likewise, the code should react most quickly if an invalid user or one previously associated with attacks is associated with a service call. It is more important that these checks are done before checks that test whether a field contains a valid data type or a value within some range.

Validation-4 : Identify and prioritise the validation checks that are applied to the parameter values of service methods. Order the validation checks so they
  • cause validation to fail as quickly as possible and
  • wherever possible, give highest priority to fail a security validation check over other types of checks
  • minimise the load placed on the database.

We identified and ordered a number of validation checks for a typical service call and described them in the table below. As well as the order, the table describes what class is responsible for holding the code for a check and the classes that actually call that code. For example, the code to determine whether the fields of a User are valid is inside the checkErrors() method in that class. However, user.checkErrors() is actually invoked in the service methods that appear in the services classes such as rifServices.dataStorageLayer.AbstractRIFStudyRetrievalService and rifServices.dataStorageLayer.AbstractRIFStudySubmissionService. Where the code is owned and where it is called help show how validation duties are distributed in the layers of the code base.

The table also shows whether a check requires the database. Checking whether the field values of a Geography has a valid value for its 'name' field does not require a call to the database. However, knowing whether the geography "SAHSU" is known does require a call. Note that in the starred item marked '**', users are checked against a black list that is managed in memory, not in the database.

Priority Order Description Where code for check exists Where check is invoked Need access to the database
1 Check that the user object has not been previously black listed due to previous security violations. Reject if user object is null. SQLConnectionManager service classes No **
2 Check that parameter values are not null FieldValidationUtility service classes No
3 Check that the user Object contains no malicious field values. User service classes No
4 Check that all the field values in the User object are valid. business classes service classes No
5 Check that the userID is currently registered. SQLConnectionManager service classes No
6 Check that none of the fields of any of the other business objects besides User has no malicious field values business classes service classes No
7 Check that the fields of other business objects besides User:
  • have no missing required values
  • have values which can be converted to an appropriate type (eg: a year String field contains a value which has exactly four digits)
  • have values which are within the constraints of the value (eg: the year is reasonable)
  • have field values which are valid individually, but which are invalid in combination. (eg: In Investigation, a start year of "2001" and an end year of "1999".
business classes manager classes No
8 In some cases, check whether parameter values exist in the database manager classes manager classes Yes

Tour of Validation

Search for the tag TOUR_VALIDATION in the code base. The results will show you examples of how code supports validation checks described in this section.