2

In a Web Application that has 4 layers:

  • UI layer
  • Business layer
  • Data Access layer
  • Data storage layer which is the database

One of the requirements is to handle a list of objects with unique key. For the database it is obvious that I need to use a unique key constraint on one column.

My understanding to handle duplicate keys should be handled by the database. For example, When a user wants to add new entity with duplicate key, all three layers above data storage have to do no validation. Saving the entry to the database will throw an exception and a proper error message will be propagated back to the UI.

However, one of my colleague said this is not a proper design: Each layer should not rely on other layers. And suggested to handle the duplicate key rule in the data access layer also. The reason He had: Imagine this scenario, changing the database to have a plain file instead so we can not leverage the unique keys constraint.

But if I agree with him, there are many drawbacks also:

  • Duplicate validation (4 validations) in all layers: I have to do the same validation for business and UI layers too.
  • Performance issues: Figure out proper data structure and algorithms to handle validation. Imagine a more complex validation scenario like multiple keys, big collection to handle in the memory...

What is the proper way to handle these kind of validation in a Web Application?

  • I'd say that there must be a layer concerned with validation of this particular constraint. This is most easily done at the database layer when you have an RDBMS. It can be a different layer when you don't (e.g. when you use a distributed / eventually consistent DB). – 9000 May 14 '18 at 17:50
4

However, one of my colleague said this is not a proper design: Each layer should not rely on other layers. And suggested to handle the duplicate key rule in the data access layer also. The reason He had: Imagine this scenario, changing the database to have a plain file instead so we can not leverage the unique keys constraint.

Your colleague is close here. The problem is not that layers in general should not trust each other. In fact, they should trust each other with certain concerns. The problem is that other layers are concerned with this validation because of the fact that the DBMS might change to a system that cannot be trusted with this responsibility.

The question you have to ask yourself is, how likely is it that you will replace your DBMS with a system that cannot enforce this constraint?

If that replacement is not likely, then the only benefits of redundant validations are looser coupling and not having to traverse application layers unnecessarily (think of not validating redundantly as making an API call with a request that you know might be invalid).

Assuming that the risk of DBMS replacement is likely enough to offset the maintenance cost of redundant validations, let's think about each layer:

UI Layer (don't validate)

The only benefit of validating here is the instant feedback to the user, and the drawbacks are the scalability/security issues of needing to expose all existing keys to the UI to perform the validation. While this may be possible if your architecture and data set allow for it, it is probably not ideal unless it is a hard UX requirement that the validation be done locally (and presumably it's not, as it is currently not performing the validation).

Business and Data Access Layers (validate in one of these)

If you're following a repository pattern or something similar for your data-access layer, it's probably a good idea to treat the validation as business logic and put it in the business layer. If you're following the broader data-access layer pattern, however, it might make more sense to separate that data model knowledge from the business logic. (There is some confusion around the differences between these two types of data access layer, and what the responsibilities of a data access layer should be.)

Remember that the only reason we're validating here is that we're assuming that the DBMS cannot be trusted with that responsibility; as such, to maintain valid separation of this concern, you should choose one of these two layers to be responsible for the validation, not both.

Data Storage Layer (validate)

At first glance, it might seem like adding a unique constraint here as you suggested is violating the trust of the business or data-access layer and overlapping concerns too much. However, remember that this layer, being a DBMS, is concerned with data integrity (e.g. normalization). As such, it is an overlapping concern, and the database has every right to enforce such integrity by leveraging constraints.

More practically speaking, this is a prudent way to ensure that no invalid data are created by mistake. Bear in mind that the data access layer may not be the only entity creating/modifying data to this database. The mere fact that human users with database credentials may log in and create data directly is enough to scare me into violating any SoC purism that might exist here (though it's my opinion that none does).

Summary

  • Separate concerns appropriately, and acknowledge when a concern overlaps layers.
  • Use redundant validations when you want to account for future abdication of responsibility or reduce unnecessary layer traversals.

In this particular case, I would add the database constraint and validate in the business layer or data access layer (not both), depending on how you've defined the responsibilities of your data access layer.

2

The problem with validating uniqueness is that you need to know about all the other records.

This normally means that yes, you can only validate on the database as this is the most efficient point at which to check for duplicates.

You could of course do this on any layer, as long as you kept a list of all the other keys any checked though them.

I would however suggest you bypass all these problems and simply used GUIDs. In which case you can generate the keys on any or all layers and be sure that every one is unique without having to check.

0

Put simply, your colleague is wrong. Ask yourself, what are the stakeholders in your system that require this uniqueness? Why does the key need to be unique at all? The answer to these questions is almost always your persistence layer. Uniqueness is rarely important outside of your persistence layer (which cares about things like normalization). Beyond that, it is simply untenable to enforce a unique constraint for sets that include large numbers of records.

Whether or not your data source is an RDBMS or a text file is not relevant. Repository implementations must be persistence-aware, so changing your data source will certainly require changes to your persistence layer. That makes sense right? Changing your storage medium requires changing the persistence layer. If you can no longer rely on a database constraint, then you will need to add the code necessary to enforce uniqueness for text files (in the persistence layer). Simple.

What doesn't change, and this is the important part, is the interface. The contract between your upper layers and persistence will be the same. In either case it looks like:

UniqueDomainModel model = repo.FindByUniqueField('some unique value')

model.ExecuteActionThatChangesUniqueField()

// throws FieldMustBeUniqueException
repo.save(model)

There is nothing to be gained by having a repo.IsFieldUnique('some possibly unique value') method. Tell, don't ask.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.