Dynamic UI: When is UI Logic considered Business Logic?

Dynamic UI: When is UI Logic considered Business Logic?

Old forum URL: forums.lhotka.net/forums/t/4239.aspx


NightOwl888 posted on Friday, January 25, 2008

Hi,

I have been struggling with this one for awhile. I have an ASP.NET application that allows an administrator to choose what type of controls to put in a collection of product attributes.  There are currently 3 choices: a text box, a read-only label or a dropdown list. I am planning to add 2 more choices to the control type list - however, I am just now to the point of rebuilding this page to use CSLA business objects.

Here is something like what the list of controls will look like when the controls are added to the UI: http://www.shuttercontractor.com/products/louver-shutters/vinyl-shutters/custom-made-shutters/mid-america-L2.aspx

A couple of things to note about this page:

  1. The number of dropdowns on the form (and their values) are dynamic. This is completely depending on the product we are referring to.
  2. Some rules are intersparsed among user selections of the (dynamic) dropdowns.  For example, the item should be invalid if the user selects anything other than 14 1/2" from the Width dropdown and selects "yes" from the 1/4 Round Arch Top dropdown.

My object hierarchy is as follows:

Item > AttributeList > Attribute > AttributeValueList > AttributeValue

The part I am struggling with is when the user selects an Attribute Value from the dropdown, my Attribute BO must know what type of control it is dealing with to perform additional logic.  Since the type of control is stored in the database, I have access to this value, but it seems like this is technically UI logic.

On the other hand, if I push this logic to the UI, the UI will have to know about the busines rules (such as the one that I described in #2). The UI already has to know whether to update the Attribute Value ID field (the key) or the Attribute Value field (the value from a textbox or the text in the dropdown), and I don't think there is any way around this one.

To complicate matters further, the actual calculation of the price is going to be dependent on the product.  There will be 2 different calculations - one just adding the values of the prices in the dropdowns (the "standard" way) and another calculating based on square foot price (meaning the height and width will have a different calculation than the other values). This means my Item BO needs to know the "attribute category" of each of its attributes in order to determine which one contains the value the business logic is ineterested in.

I have been thinking about trying to subclass these different cases instead of using select case logic in the calculations and business rules to simplify the calculations and also the attribute control types, but I am not sure whether subclassing items that are in a collection will work. I imagine I can store them there and I would have to cast to my subclass type in order to work with them (which seems like it would push logic into my collections AND my UI on what subclass to cast to before running the calculation/logic). Subclassing my (root) item almost seems like overkill, but it is highly likely there will be other price calculation methods in the future.

First of all, I would like to know if anyone has tried creating a dynamic UI like this one and could use some guidence on how it was accomplished and where the business logic/UI logic ended up.  Seconly, I would like to know if someone has stored "oddball" subclass items in a collection and used inheritance to solve issues with complicated business logic and if there are any drawbacks that I should know about before attempting this approach.

TIA

-NightOwl888

ajj3085 replied on Friday, January 25, 2008

Hi,

The link you posted doesn't seem to work, so I'm not sure if I'm missing the point.

I think the key though is your use case; the admin isn't putting "controls" on a product page.  There's some input (or not, in the case of a label) that sounds like metadata around the product.  So your use case is that the users can enter a free form value, pick from a list, or the value cannot be set, only read.

I may have had something similar; I have line items in an order, for example.  I needed a way to add arbitrary metadata to any type of line item.  For example, we have a packing fee line item, which automatically computers a packing fee, and enforces a $10 minimum.  Except my users needed a way to turn off this minimum.  No other line item should have this property, so it wasn't appropriate to add it to the base class.

What I did was create a LineItemOption.  Each type of line item can contain any number of options.  The UI can request a list of options as well as their option values (which are always of type "object").  The LineItemOption gives a friendly description of the option, and has a System.Type Type property that indicates what type value the option accepts.  So continuing my example above, the Type would indicate System.Boolean. 

The UI uses the GetOptions, GetOptionValue and SetOptionValue to determine how to build the UI, which in my case is a context menu.  The UI will use a menuitem that can be "checked" if it find a boolean, a TextBox if the Type is string, etc. 

In this way, any UI can figure out what options a line item may have, and its up tot he UI to figure out the best way to allow the user to get or set the option value.  You may be able to do something similar, although more complex because of your "choose a value from the list," but I think it can be workable.

The SetOptionValue sets the appropriate private field in the PackingLineItem, and when called will verify that value is a boolean (by checking value.GetType() against what LineItemOption says it should be) and then call MarkDirty, which triggers a Unknown PropertyChanged event.

HTH
Andy

NightOwl888 replied on Friday, January 25, 2008

Sorry, I modified the link shortly after I posted it - I was pointing to the test environment which isn't available to the general public.

I think you hit the nail on the head here. I am thinking in terms of UI, when I should be thinking in more generic terms. Now it is clear that my logic revolving around the "controls" belongs in my BO.

Things are still a little fuzzy as to how your LineItemOption solution actually worked, though.  In particualar how did you implement any business logic that was dependent on more than one of these options?

ajj3085 replied on Friday, January 25, 2008

So far there's no business logic linked to these properties.  That may be a part of the puzzle you'll need to figure out yourself and report back on.  Smile [:)]

As I said, so far the only options allow the behavior to be modified slightly; either the Packing item does or does not enforce the minimum fee.  Other "fee" items can be credits, or not (if they are credits they negate themselves).

NightOwl888 replied on Friday, January 25, 2008

Okay, I guess it is back to the drawing board.  I wish things were that simple in my case, but for square foot price calculations, my attributes won't be able to calculate themselves because they need ot know values of their siblings. Same goes for the business rules.

So, it looks like it is up to my Item object to make that calculation.

Anyway, it sounds like you have a collection of type object that you use to store your value selections? Am I interpreting this correctly? Or is it just a property of type object on your Option?

ajj3085 replied on Friday, January 25, 2008

Well, you can expand what I've done.

alternately, since you have more details, you may need to create different Product classes; one for products that have dimensions, one for those that don't.  The use cases are different, so different classes may be required.

NightOwl888 replied on Friday, January 25, 2008

In my case, I separated the concept of "product" and "item".  A product is something that can be edited by an administrator or viewed by a customer.  An item is something that is edited by a customer and added to a shopping cart.

One of the things my original post talked about doing was subclassing the item and some of the attributes (in your case options) of the item. However, being that both objects belong to collections will contain a mixed bag of subclasses, I am uncertain how this would work exactly.  It seems like I would need to cast every object in the collection to the correct type before any of the overridden methods would function in the subclass - I don't remember and it has been awhile since I have tried something like this.

ajj3085 replied on Friday, January 25, 2008

If you need to do lots of casting, you're probably mixing your objects too much, which means you're trying to use them for multiple use cases.  Design the objects for each use case completely seperately, and then later if the behavior is identical across all the use cases you can reuse them.

Your idea to seperate Items from products is a good one, because each class is fulfulling a different role.  I do that too; I have LineItems and products.  You can create a line item from a product, but it mearly copies data into the line item at whcih point its independant of the product.

Copyright (c) Marimer LLC