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.
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.
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.
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.