3

Situation:

VB.NET WinForms application, using the WinForms as a presentation layer project. Another class library project containing the business layer, in the form of CQS and Service classes, plus a data access layer.

Summary:

I'm attempting to follow CQS for new features being added to the legacy application. Consider a product return log... I have a class for the Update Command, a class for the Create Command, and a class with two Query functions. The ProductReturnsService class contains the Public functions for the Windows Form to call Create, Update, ReadX, ReadY, etc. This class also contains private functions to validate the Update and Create commands.

Dilemma:

When updating an item on the product return log, I need the UI to disable several controls based on the current or changed data for the item being updated. For example, I have a CheckBox called "Completed", which will "close" that product return record and lock out changes to all the other fields. However, this CheckBox shouldn't be enabled unless, for example, Date Received has a value. The "Completed" CheckBox also shouldn't be enabled if the current user isn't a member of a certain security group in the system - even though that current user can enter data.

Question:

In OOP, it is my understanding that things like, "Can't check Completed until Receive Date has a value." and "Can't check Completed if not in the Manager role." are business rules. And it is my understanding that business rules belong in the business layer.

How do I expose those business rules to the UI, so that users aren't frustrated with returned validation error messages from the BL? How can I have the UI enable/disable controls according to the business rules in the BL? I also understand that following DRY, I wouldn't want to recode all the business rules in the Windows Form code page.

I can't wrap my head around how to implement one set of business rules that the BL acts on, as well as the UI. Currently, my BL validation is in the ProductReturnsService class, with one function to validate a Create Command, and another function to validate an Update Command, which I think makes sense because these validation functions are validating the data before it goes to the database. I would prefer the same kind of validation "in real time", interactively, on the UI.

HardCode
  • 674

2 Answers2

1

The only way to get those decisions out of the UI, is to have the "business" objects generate / control the UI.

You have to decide, either the UI depends on business things, or the other way around. You must choose at least one, and if you're doing it wrong you will have both.

Traditionally people tend to want the business layer completely separate from the UI. This works if you need to support unknown UIs that you don't control. This is what a traditional "layered architecture" does.

If however you want to go in the direction of really having knowledge localized, and you control the UI anyway, you can let UI things into the "business" objects, to be able to keep UI logic free. Fair warning: people seem to have a natural aversion to this design for some reason, you'll be probably on your own if you attempt this. There's no other way to do what you're asking for though.

0

It's not "Business Logic" is presentation layer.

For example you can imagine the same form done in multiple ways, a popup warning about the validation error, the checkbox being invisible, grayed out, validation after submit, ignoring invalid items, auto fill today's date etc etc

Sure the presentation choices you make are also "logic that is decided by the business" its just an arbitrary division between stuff that must always happen regardless of the presentation, and stuff that happens on some screens and not on others, or other imagined screens

As to how to implement ther functionality if you choose to put the logic in the business object, its simple enough you just have to expose a property on your business object that reflects its state

class Return
{
   DateTime ReturnDate
   bool Completed
   bool IsCompletable //Logic in BL
}

MyForm { Return return CheckBox CompleteCheckBox

//logic in BL OnChange() { //you'll have to think about the method to choose here I dont remember my winForms if(return.IsCompletable) CompleteCheckBox.Disabled = true }

//logic in View OnChange() { if(return.ReturnDate == null) CompleteCheckBox.Disabled = true } }

Ewan
  • 83,178