Re: Long Life Objects



Responding to Timeisfire8...

Why do you want to use the Dictionaries as buffers in the DB Access
layer? Is this a performance issue (i.e., read the DB once at startup
and emulate it in memory to avoid individual seeks)?


Yes that is the reason, I don't have a performance issue that requires
the use of this approach but it just seemed like a more efficient
design than pulling the same (relatively) static data over the wire
from the RDB repeatedly.


Is the application up 24x7 or heavily multi-user so that the same customers keep getting
re-accessed and you wish to avoid redundant DB accesses?


Yes to 24x7 and I would say light multi-user access. The RDB hardware
and network have an excellent spec.

OK, then my push back is the same. You can implement the cache either in Dictionaries, which emulate the table-based searches of the RDB, or you can implement the cache in the OO model structure. I would opt for doing it as in the OO model because that maps nicely to the customer problem space.

It won't help for the Company/Customer search but it should be more efficient for Customer/Contact. And if there are other objects that collaborate with specific Customers or Contacts during other warehousing processing, it should help there as well. (Your BillingAddress example below is an example.)

So the only "address" is an eMail address string? (I assumed it was a
classic mailing address composed of {street, city, etc.}.)


Your assumption was correct, sorry I didn't change your diagram.
Address is a classic mailing address. I have designed email address as
a string attribute of Contact.

OK. Whether you need a separate object for it depends on the situation. Even in an RDB one usually denormalizes to avoid tables where the only fields are elements of a compound key. So if there is exactly one mailing address per Customer or per Contact, one would usually just tuck the attributes like City there. OTOH, ...

That brings me full circle to my questions about performance above. This
warehouse application may be doing lots of other fascinating things, but
accessing contact information seems like it is pure CRUD/USER
processing. It also seems like ad hoc processing in that the user is
going to provide an arbitrary name and you give back the Contact
information that is in the DB. That is exactly what RDBs do best and you
are emulating it in memory. If that is the case, I would be inclined to
forget about [Contact] completely. I would just invoke a DB Access
interface method like getContact(customerName, contactSelector) and let
the RDB do its thing.


Yes it does perform other tasks but it is mostly CRUD/USER processing.
It seems that I have been protecting the RDB when I should have been
putting it to work and saving myself the additional work of managing a
domain layer in-memory database. This in fact might answer the
thread's original question where I was seeking advice for the object
that should be responsible for creating my application's 'type'
objects. To recap, my Address object currently contains an AddressType
object. Although some AddressTypes are known at design time (billing,
delivery etc.), the app allows a user to create new ones via the GUI.
I cannot therefore build a class hierarchy of AddressTypes at design
time. Therefore my current design simply instantiates an instance of
AddressType with data from the RDB and that instance is held as an
attribute of an Address instance. This approach is substituting sub-
typing for a reliance on the unique ID AddressTypeID so that tests for
an address type must check the int based ID against an application
constant. For example, in the billing area I would need something
like:
const int BillingAddress = 3;
if (Address.AddressType.AddressTypeID == BillingAddress )

This seems messy but I cannot find a way to handle such application
'type' objects that are not known at design time. How do you deal with
this sort of situation?

I think the messiness is just a symptom of not being faithful to the problem domain's structure. This is a situation where one has multiple relationships to an Address. (By implication, one also could have multiple Addresses per Customer or Contact.) So an Address needs to be abstracted as a first class object.

Presumably there is an an object somewhere that is responsible for collecting billing information and shipping it off to your Invoicing application. To do that the object needs the Customer's billing address. IOW, the only address it needs among the many the Customer has is the one with type BillingAddress. (Or at least it has to distinguish between things like BillingAddress and ShippingAddress.) One can do that directly with relationships. For example,

[Shipper] [Invoicer]
| 1 |
| |
| R1 | R2
| |
+----- [Customer] -----+
ships to * | 1 | 1 * bills for
| |
R3 | | R4
| |
uses for | | uses for
shipping | | billing
1 | | 1
[Address]

In your case the number of flavors of Address for a each Customer is probably fixed and quite limited, so you could implement R3 and R4 as individual pointer referential attributes in [Customer]. That completely eliminates any searching for addresses; the client just navigates the right relationship by accessing the right pointer reference.

But even if the flavors of Address are more dynamically flexible you could still do:

[Shipper] [Invoicer]
| 1 |
| |
| R1 | R2
| |
+----- [Customer] -----+
ships to 1 | 1 * bills for
|
| R3
|
| has
| *
[Address]
+ addressType

The Shipper and Invoicer now need to search the R3 set of addresses to get the right type, but that set will be a whole lot smaller than the total set of addresses one would need to search to find the right customer in an AddressType dictionary. IOW, the R3 collection just optimizes the search scope to the smaller set of individual customer addresses rather than the larger scope of all addresses of a given type.

As an added bonus, every object is clearly a problem space entity while the details of collections are abstracted as simple associations that reflect existing relationships in the problem space. In contrast, in your solution each Dictionary is a first class object in the OOA/D even though it doesn't directly represent an entity in the problem space. [Try talking to the warehouse foreman about AddressType entities. B-)]

One way this bonus is manifested is that there is a quite natural** flow to the relationship navigation. The Shipper or Invoicer is very likely to already have a specific Customer in hand. Navigating R3 to get the Address is directly utilizing a relationship that already exists in the problem space. That contrasts with navigating through Company to access an AddressType dictionary; it would be a very tough sell to a reviewer that the problem space was organized that way.

Keeping faith to the problem space structure is desirable because software customers don't like change any more than software developers. So customers will implement change in their environment in a manner that causes minimal disruption to the way they already do things. So when change filters down to the software s requirements, the customer will already have identified the path of least resistance and the change should by no more difficult to implement in software than in the customer space -- provided the software structure emulates the customer's problem space structure.

** natural, of course, is somewhat biased by my having spent three decades doing OOA/D. B-)



*************
There is nothing wrong with me that could
not be cured by a capful of Drano.

H. S. Lahman
hsl@xxxxxxxxxxxxxxxxx
Pathfinder Solutions
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development". Email
info@xxxxxxxxxxxxxxxxx for your copy.
Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH



.



Relevant Pages

  • Re: Long Life Objects
    ... customer in an AddressType dictionary. ... every object is clearly a problem space entity while ... delivery address created for any customer from that point on would be ...
    (comp.object)
  • Re: Long Life Objects
    ... Thanks for your continued detailed posts Lahman. ... customer in an AddressType dictionary. ... every object is clearly a problem space entity while ...
    (comp.object)
  • Re: modularity... (was: Re: Looking for real world examples to explain the difference between proced
    ... That's what problem space abstraction provides. ... customer: the one who specifies the requirements for the software ... my planned alterations to the compiler core should be able to ... one configured it with an external BNF description of the language to be ...
    (comp.object)
  • Re: distorted model! do i need patterns or something!?
    ... In the problem space things like Hotel, Section, and Room are important entities and they have well-defined relationships. ... That allows quite generic code to be written for relationship implementation, instantiation, and navigation that is very aspect-like. ... the customer doesn't like change any more that software developers do. ...
    (comp.software.patterns)
  • Re: Creating a "toy" OO/AO language...
    ... That just doesn't seem like a reasonable abstraction of the problem space when the unit, the meter, and the tenant haven't moved and the service was uninterrupted. ... For one thing utilities usually have ridiculously complex classification schemes for the services (residential service to an over-65 customer with veteran status on the wrong side of the tracks in a unit with R45 insulation). ... name one such methodology outside OOA/D/P. ... closures play together well with other FP construction elements. ...
    (comp.object)