3

I have an app which accepts two parameters: payment received and cost. It then calculates change denominations.

It is an MVP app, which calls a WCF web service, which accesses a Domain Layer DLL.

Say a user enters £1 for the payment received and £2 for the cost. Clearly this is wrong (there is not enough money). I have two questions:

  1. Where should the application handle this validation logic. In the presenter? In the Domain Layer?
  2. Should the application throw an exception or return a message?

Say the user enters the same value for payment received and cost (same two questions above apply).

This article, Validating with a Service Layer (C#), talks about doing validation in the service layer. I like this idea as it means all the clients (MVP, MVC, Mobile, WPF etc.) can use the validation.

However, does this make the domain model anaemic rather than rich?

2

Assuming that, notwithstanding the reasonable doubt put forward in VoiceOfUnreason's answer, the business rule has been firmly decided on, as your question assumes.

Then the simple answer is that no system should trust its input, especially (but not exclusively) when the input comes from a human user.

So validate on every level.

If you persist your data, you should implement this check in your data model and deal with exceptions in your DAL (data access layer). From there, you can throw exceptions to be caught by your BLL (business logic layer) that uses that DAL.

Your domain layer should implement the business rule in its model as well. Sometimes the domain is generated at least in part from the data model, so it would automatically end up there. Again, you can throw an exception if the rule is violated.

Your WCF service can throw an exception too. This is widely considered a good thing, as long as you describe the possible exceptions your service may throw in your service contract.

Now you have protected your back-end from corrupt data, but it would mean you have to call your WCF service after user input, just to find out that there is an error. It is common practice to validate user input on the front-end without calling back-end services first, if such validation can be done based on the user input itself (checking for an existing user-name cannot be done like that of course, but checking whether a start-date lies before an end-date is common).

This you can easily do in the model in your application, using, for instance, data-annotations and validation. In this case, you provide validation messages that are meant to be sent to the end user.

Before submitting the user data to your WCF service, you validate the data, and if there is a validation error, your tell the user.

  • Thanks. Your answer seems to suggest that you do the validation at every layer. Is that right? – w0051977 Jun 15 '17 at 18:52
  • Yes, indeed. Every layer may get its input at some point form misbehaving clients, so never, ever trust your input :) – oerkelens Jun 15 '17 at 19:06
  • I have edited my OP (see last paragraph). Could you take a look? – w0051977 Jun 15 '17 at 20:05
  • @w0051977 That article just covers an MVC application directly accessing a repository. Your WCF should certainly take care of its own validation. You can use the same domain models with their validation in both your front- and back-end, of course! – oerkelens Jun 15 '17 at 20:28
  • 1
    The validation is on different levels for different purposes. On the UI level because it is inconvenient to the user if mistakes are not corrected as early as possible. On the server to prevent fraud. – gnasher729 Jun 16 '17 at 9:16
1

Say a user enters £1 for the payment received and £2 for the cost. Clearly this is wrong (there is not enough money).

There are really two different answers to that.

From the point of view of the domain model, you need to think about whether this is a real business event to track, just a data entry error, or a data entry error that you want to track. There's nothing fundamentally impossible about paying less than the cost (manager comping somebody? coupon?), so the domain model should be choosing its own policy for handling this case.

That said... if data entry errors are much more likely than accepting less than the cost as a payment, then a reasonable answer is to use a task based UI approach; which is to say you present a UI that requires that the operator either input a payment sufficient to cover the cost OR that operator shift to a different UI that is more forgiving (think manager having an override).

  • Thanks for answering but I do not understand your answer. Are you saying that if a user enters an invalid amount then forward them onto another page that allows them to enter an invalid amount? – w0051977 Jun 15 '17 at 18:06
  • Please assume that this is all the app will be. – w0051977 Jun 15 '17 at 18:10
  • @TheCatWhisperer, could you explain what you mean by: "specify the model context". Thank you. – w0051977 Jun 15 '17 at 20:03
  • "From the point of view of the domain model" – TheCatWhisperer Jun 16 '17 at 14:15
1

I tend to agree with oerkelens in general (never trust your inputs), but there's some important caveats to mention. Because if you naively put checks in every function of every layer, this will have an impact on performance.

I follow a general rule that I summarize as "Check everything that needs checking as close as possible to the source of the input."

And this means different things for different cases:

  • possibility of values depends on the nature of the data (eg costs cannot be negative, counts have to be integers, ...). Hence this should be checked as close as possible to the input, preferably by not allowing the user to enter negative values in the UI. So this check is in the outer layer.

  • feasibility of values depends on the actual use case. I can imagine that the same UI is used in a case where business rules say cost can't be higher than received payment, and in another case where this actually can happen. So those checks I'd put in the WCF service that's used in that specific use case. Your UI side can be reused, and the DLL doesn't need to be called when the data does not comply.

  • useability of values depends on the underlying algorithm. Even with the rules above you can have a cost of 0 and a payment of 0. But if you want to do a calculation where you use a log-transformation, this will cause -Infinity trouble. So the actual method cannot deal with values that are 0 or smaller, and hence that method should check its input before it starts doing the calculations.

I am aware that this can't be set in stone and some ambiguity will remain, but it's in my humble opinion the best general approach to validation checking.

Regarding the reporting: Always give your users an understandible and explanatory message about what went wrong and why it went wrong. Even in the second and third case, catching exceptions and translating them in useful information for the end user should be a second nature for every programmer. Again in my humble opinion.

  • Thanks. With regards to bullet point two - does this make the domain model anemic? – w0051977 Jun 16 '17 at 10:48
  • @w0051977 I'd rather call it "lean" than "anemic". It depends ofcourse how much other work it has to do, and in my field (statistical computing) that's where we run the actual calculations on simulations, predictions etc. So plenty of tasks. I also don't really see a problem: even an anemic domain model can still be functional and help in structuring the code in a logical way. – Joris Meys Jun 16 '17 at 11:13
  • ,thanks. I understand the benefits of an anemic model, however I am asking this question in the context of a rich domain model. Could you modify your answer? Thanks again. – w0051977 Jun 16 '17 at 11:18
  • @w0051977 I think we misunderstand eachother. I'm not saying my approach results in an anemic domain model. All calculations and the necessary checks (eg input > 0 for a log) are still in the domain. In the app I'm currently working on, the domain code is still a multifold of all the rest, so I'd still call that a rich domain. I also don't believe in the juxtaposition of rich domain versus anemic domain. I do understand, but my approach fits neither perfectly, so call it a "middle-class domain model" if you must. – Joris Meys Jun 16 '17 at 11:24

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.