1

TL; DR

Where/When to check data format in MVVM + Repository Pattern is the best practice? Any suggestion or theory?

The Scene

Our team is working on an Android Project. We have a MVVM+repo structure:

View > View Model > Repository > Model

In some feature, we need to pass data from View all way through the struct, such as "Uploading an Item":

Input
[data] --------------------------->
View > View Model > Repository > Model

Due to design, data need to match specific format, Such as "check if it is an email", "check if it exceeds 200 characters", etc. If it doesn't, show errors at View:

Output
[error] <- [- - - somewhere - - -]
View > View Model > Repository > Model

The question comes along with this process: If there's a need to check if data is format-correct, when or where to check is the best practice?

The Options and Thoughts

According to the structure, there's a few options to do format-check/block:

  1. View / View Model
  2. Repository / Model
  3. Others
  4. All

For us, we feel all of the options seems legit, yet some risks also.

View or View Model

In my understanding, View Model combines the data input by user, and send them to repository. In some situation even View can achieve the format checks, ex. Android EditText can auto-check length or legit characters.

However, making format-check in V/VM implies that some business logic might come into V/VM layer. For example, checking that "if data has already been added into database" is not appropriate to do in V/VM.

Repository or Model

This is the most attractive answer so far -- if we put checking function here, we can also include the business logic here, making it easier to manage logic part (and feeling less guilty lol).

However, if the View requires instant-check, then putting all the checking functions here might cause the Repo unnecessary-fat.

For example, imagine a form View with 4 fields, each of it has its own format-limit, such as length, characters, regex, or even cross-field relations (if A is checked then B is not allowed to write, etc.).

If we put data-checking functions all inside Repo, this means that Repo has to provide at least 4 data-checking functions, and still having difficulty to deal with cross-field relations, AND still need to provide the sendOutForm functions.

Util or Helper class

Another option comes in mind is the helper/util class. It might be appropriate, however it has the same questions as View option: some business logic is not viable in util class, and helper class (with too many reference/logic) might also cause function management problem.

Check More/All: Pros and Cons

Ideally, making format-checks as many as we can is the most secure option. However, it will reduce function flexibility.

For example: the data originally requires description field to be necessary, but later decided to make it optional after the product published a while. If we make null/empty checks of description field at all places, it will cause a lot of time to make the updates, taking more time to check where hasn't been modified.


That's all of our thoughts now. How would you archive the data-check? And why? I'd like to know.

4
  • I interpret "data format check" as rules like "must be a valid e-mail" (e.g. [email protected]) or a phone number adheres to a certain format: nnn-nnn-nnnn. Your question appears to talk about other rules, which I would broadly define as "validation rules." Can you clarify what you mean by "check data format?" Apr 27, 2022 at 12:03
  • @GregBurghardt actually I treated them as the same before, since they are both validating if the data is legal. But many of others tell me that "format check" v.s. "validation rule" might be different types, and I think they got a point. You may elaborate your thoughts about differences of these 2 types, and how do you place/run them, in an answer. Then this might an accepted one :) Apr 28, 2022 at 2:11
  • In layers. The view does some checks (constraining the string). The view model does more (to determine if it can create a date from the string for example). By the time the data hits the model it should be valid, but not be valid for this or that usecase, so those business rules would do further validation.
    – Kain0_0
    Apr 28, 2022 at 4:12
  • See related question Clean architecture validation in domain vs data persistence layer
    – John Wu
    Apr 29, 2022 at 7:33

3 Answers 3

1

When working with code architectures like MVVM, MVC, ... The questions about data validation, data formatting, ... arise frequently.

What I like to do personally is to have a fast validation on the view to warn the user about the most basic mistake he can make and a more complex validation in the model containing both the validation coming from the view and additional rules.

For example on an email you check the format in the view and in the model you check the format, whether it fits in your database, whether it already exists in your database, if the email provider is an authorized one, ...

This causes some checks to be done several times (only the fast checks are done several times and with the computing power we have nowadays this shouldn't slow your app too much) but it lets the user have a quick feedback and ensure your code will have the correct data when it will have to handle it.

I know that a lots of people have different opinion on the subject. This could maybe be considered opinion based...

1
  • 1
    Checking email addresses correctly is difficult. And few things are more annoying than trying to enter your own email address and some stupid software telling you that it is not valid.
    – gnasher729
    Sep 29, 2022 at 16:16
1

I would personally do validation on the model. Reason being repository is just for interfacing with data persistence layer. It shouldn't do any validation but only accept already validated requests. If model does the validation then you can't construct an instance of the model that is invalid which is the best in my opinion. If you put validation in a helper, you may forget to call it. With this approach you can't.

Though for user experience I would also validate on view layer. But I wouldn't rely on view layer in the model.

0

Firstly, you should put checks in place at the view level, which will give your users idea of what your app accepts, e.g character limit for an email body. If that's exceeded, you could e.g disable "Send" button or upon pressing the Send button, you show a modal dialog with an explanation of the error.

On Android, the architecture that is getting the most traction is a MVVM with Clean Architecture that looks like yours but also includes an idea of Use Cases between your view/view model and repository layer. The use cases are "bite-size" classes that contain business logic and that is where I would suggest you put the logic related to whether to send an email or not or whatever else you want to do.

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