Brennan Hoeting
Brennan Hoeting

Reputation: 1213

OOP: Should valid data be handled in the class or the frontend?

Let's say I have a polygon class. Its only private data is an array of points. Should the class be written assuming the array has at least 3 points, and the GUI or input part of the program makes sure there are three points? Or should the member functions test the data validity and return an error message if needed?

Upvotes: 2

Views: 176

Answers (4)

ahoffer
ahoffer

Reputation: 6526

There are some good points in the other answers. I'll try and state them here:

  • Ultimately, the model is responsible for knowing if it is in a valid state or not.
  • The UI needs to be aware if the model is in a valid state.
  • The UI can protect the model from invalid states AND provide good user feedback by validating the inputs.

There are some challenges:

  • If the model and UI both have validation code, the result is either duplicated code in the model/UI or a split between between the model and UI of the validation responsibilities.
  • UI validation gets messy because some data fields depend on others. Imagine an application that collects zip code and state (for US postal addresses). If you change the state, do you want the UI to immediately pop a dialogue box that says "Invalid zip code"? No. That would be annoying. The UI should give the user a chance to put the model into a valid state.
  • Throwing exceptions to catch validation errors is a heavy-handed way of doing things. Usually, you will want something less obtrusive.

Here is what I like to do for complex validation:

  • Allow the user the enter invalid values.
  • Create a class called ValidationError that includes a human-readable description of a single validation error.
  • Provide model methods like getValidationErrors() and isValid().
  • Before committing any changes to the model, have the UI call isValid() and getValidationErrors(). If there are any validation errors, make the UI display the errors to the user. Prevent the user from continuing until the errors are fixed.

The advantages of this approach are: - More control of validation. You can decide when and what you want to validate. - Centralizes validation logic in the model. The UI is only responsible for getting and displaying errors generated by the model. - Less risk of other other code making invalid changes to a model if the model calls isValid() before calling save/commit methods. -No exception handlers.

Consider creating a ValidationRule class. Each rule contains the code to valid something and generate an error message if it is invalid. The ValidationRule class has a method validate(aModel). This is especially easy to do if your programming language supports closures or first-class functions.

This results in each model class can have a dynamic collection of ValidationRule objects it consults when isValid() or getValiationErrors() is called. Alternatively, use a visitor pattern so that the models are are completely decoupled from the validation. This is what I do in my validation frameworks.

In a distributed application where the model is not on the client, it is often wise to do some basic validation before sending changes to the server. The round-trip time between client and server can be pretty long and you don't want to send obviously invalid requests to the server.

Lastly, the validity of one object sometimes depends on data in a different object! In these situations I let validation rules accept multiple objects, and use the controller object (or I create a context object) to manage the validation at a less granular level.

Upvotes: 2

Mar Bar
Mar Bar

Reputation: 497

If the class is expected to have at least 3 points you have to ensure it through the class interface. One way to achieve this (the only and best, actually) is receiving the polygon's points in the class constructor parameters and throw an exception if the points are less than 3 (remember that in a good OOP design, exceptions must not be seen as errors, but as a violation of implicit contracts). Then, you just have to keep unmodified the values of those points. Think as if they where "final" in Java. Remember that whatever makes your object a certain polygon amongst every conceivable possible polygon is never expected to be modified. For instance, if you assigned the points in the constructor, then those points should be preserved all through the object's lifecycle both in quantity and values. Always recall the most pure definition of object in OOP: an object is a computational representation of a real life entity. If your object represents polygon P, then it should never change in order to represent another polygon or any other real life entity. And you must never create an object "Polygon" if it actually doesn't represent a real world polygon. And that is achieved only through class constructors. Following these design guides, you'll never need to add code to validate your object is a polygon inside the Polygon class, since it is a true polygon in the object paradigm. So do the try {} catch {} when creating the polygon and let the constructor throw a NotPolygonException if needed.

Upvotes: 1

David Osborne
David Osborne

Reputation: 6781

IMHO, a well-designed class will always protect its invariants. Therefore, the class must validate and always ensure it's in a valid state.

The UI can do it too or just rely on the class.

Take a look at Mark Seemann's blog post here.

Upvotes: 1

moonwave99
moonwave99

Reputation: 22817

GUI validation is just meant for user hint.

Model should be responsible for its own integrity, as data may come from different sources rather than user [e.g. a background sync].

Upvotes: 1

Related Questions