Order - OrderLine Domain Object Design

Posted by Thomas Mercer-Hursh on 17-Dec-2006 11:57

In the thread on Management of Domain Objects ( http://www.psdn.com/library/thread.jspa?threadID=2668&tstart=0 ), which was intended to focus on the issue of lifetime management of this object type, we kept getting into a discussion about the specifics of how one should design the domain objects for Order and OrderLine. Since this was a distraction from the purpose of that thread, I have created this new thread to focus specifically on the topic of Order and OrderLine, what gets bundled with what and so forth. To get the background, one should probably read the other thread first and then hopefully the new contributions will be made here.

All Replies

Posted by Thomas Mercer-Hursh on 17-Dec-2006 14:29

I readily agree that, in the context of a

customer making a change in the quantity of an item in an order

that one has to work from the context of the order. Among other

things, the quantity might be changing to zero and this might be

the only open line on the order and the whole order is being

cancelled. However, I think there are cases, such as the mass

substitution noted above, where one will want to come at the

problem by building a collection of OrderLines rather than a

Collection of Orders which contain the appropirate lines.

Certainly, one of the common cases is reporting where the

collection exists only for the purpose of reporting, e.g., a

distribution of original order dates for a back ordered item. Some

properties of the Order need to be encapsulated within this

OrderLine object, but not the whole order. Of course, there are

plenty of interesting complexities in this issue. For example,

suppose one has a Order which supports the notion of OrderLine

kits. Kits, for those who haven't experienced this particular joy,

can be used to support various kinds of interesting OP

functionality. E.g., a kit can allow entry of a single part number

which then "explodes" into a series of component lines. These

components may or may not be visible to the customer and they may

or may not be the basis by which the order is picked. Also, pricing

may be based on the kit or on its components. Kits may be fixed and

immutable except in overall quantity or they can be editable, even

potentially starting out as empty! And, business rules may require

that only whole kits be shipped or it may be possible to ship part

of a kit and back order some parts, in whole or in part. Needless

to say, all of this can make for some interesting logic. So, what

impact does this have on our partitioning? This depends on context.

In the context of the back order profile report mentioned above, we

can probably treat a kit component order line in the same way we

treat any other order line. In the case of the mass substitution,

we probably also want to treat them in a similar fashion, but there

may be some additional complexities. depending on the state of the

lines. E.g., if all lines for the item are currently in back order

because we are out of stock and we have decided to substitute a new

product ... an example would be edition 1 of a book going out of

print and deciding to ship edition 2 to all people with outstanding

back orders for edition 1, even though the two editions has

different ISBNs and EANs ...then the substitution is fairly simple.

If, however, we have an order line for 10 of a product, 6 of which

were previously shipped, then it will probably require something

fancier such as creating a new order line for the remaining 4 while

bringing the quantity remaining on the original line to zero. Now,

imagine this when the substitution is for the kit header and part

of the kit contents have shipped and part haven't! Suppose the

operation is a mass price update? This, of course, includes some

interesting business rules including the possibiltiy that we are

not allowed to update the price on any order line where the order

is already accepted ... in which case we probably have no update to

do. But, if it is a price reduction, we might be allowed to do the

update, although we might have to notify the customer in some way.

And, we might have rules prohibiting update on any order line where

the shipping request had already gone to the warehouse since we

might be printing a packing slip containing the price. So far, I

still don't see a need to pull the entire order just to process the

line. Which said, this doesn't mean that we can't have a flag in

the OrderLine which indicates whether or not a change has been made

which needs to be propagated to the Order nor that we can't have

logic in the Order which can accept a changed OrderLine and make

any other updates necessary, including possibly rejecting the

change. Suppose, for example, that we are doing an item

substitution or some other operation which is legal on a line which

has not yet produced a shipping request, but which is not legal

once the shipping request has been created and that the status of

one or more lines changes during the time we are making the change.

Well, ultimately, of course, this is just a standard problem of

optimistic locking updates and the update would fail because the

status of the line itself had changed. Bottom line, I think that

there are cases where the Order is inherently involved and we

should thus be starting with and focusing on the Order and other

cases in which we are focusing on the OrderLine and the Order as a

whole should not be involved. When these are read-only, it is

relatively simple, but even when there is the possibility of

change, I beleive that we can encapsultate that change and only

when absolutely necessary also instantiate the Order itself.

Posted by Admin on 18-Dec-2006 03:23

Thanks Thomas for this thread split off. I recognize a lot of the order processing aspects you describe.

Order processing is about dynamics. It depends on the context what should happen. And part of the "context" is:

- the role of the user (consumer, employee, etc)

- the action the user wants to perform (order approval, placing an order, stock allocation, etc)

- the type of order (placing an order via telephone is different than a take away order which will be paid in cash).

- the configuration settings (parameters to tweak the order processing)

This makes me believe that the order processing algorythms should be isolated as strategies (see Strategy design pattern). You can have a cancel-order strategy, a web-order placement strategy, a back-order strategy, etc. I don't think you can model every aspect into the Order-class itself. There are too many variants and combinations possible, which would make the Order class too complex*.

A class hierarchy won't work either in this case, since you have combinations of features (the OOABL doesn't support multiple inheritence). You might have a class hierarchy for the different types of orders, like a WebOrder, a TakeAwayOrder (or how would do call that in English , an InternalOrder. etc.

There is also the workflow aspect. When an order has been entered, it might have to be approved. So this kind of logic has to be extracted as well to make it fit into a flexible architecture.

So the employee probably picks a task/function from the application menu, something like "Order entry". Next he/she might want to add an order and he/she selects a customer**. This will define the initial context of the service request the application will make: the user, the action, the system parameters and the order type will be known. Next the application will gather some input and the user might want to post the order. The order processor, which is a potential remote service, will receive the order details and the context. It has to pick the proper strategy (or even strategies) to process the request.

I think this type of request is different from a simple "add country" request. Here all the logic can be encapsulated in a Country-class. So it will be important to divide the application in processing types.

*) this means that the Order entity class no longer encapsulates the full behavior of the order processing mechanism. So directly updating the orderline quantity will not trigger any processing, since it's the other way around: the orde processor updates the orderline quantity and the DAL is responsible for persisting this modification.

**) you might want to question if the user will first enter the products and than enter the customer or the other way around. The sequence will be important, since the system needs to know the customer to provide the proper prices and discounts. In a consumer to business website the products will probably be picked before the user is known. So this depents on the context.

Posted by Thomas Mercer-Hursh on 18-Dec-2006 11:14

And, of course,

one might want to have a system in which a busines-to-business sale

can start with the product in order to allow an operator to respond

rapicly to a telephone order, but still make everything "right"

when the customer finally identifies themselves.

This thread is closed