From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: fac41,30cdfbb433fa5e47 X-Google-Attributes: gidfac41,public X-Google-Thread: 103376,30cdfbb433fa5e47 X-Google-Attributes: gid103376,public From: Thomas Beale Subject: Re: use eiffel to build a CAM library? Date: 1998/01/22 Message-ID: <34C68DFA.136E@invest.amp.com.au> X-Deja-AN: 318162494 Content-Transfer-Encoding: 7bit References: Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Organization: AMP Investments Australia Newsgroups: comp.lang.eiffel,comp.lang.ada Date: 1998-01-22T00:00:00+00:00 List-Id: Shane Miller wrote: > in the above example, if the list of big objects contains > 100 entries and the user (after he obtains his "copy") > only modifies 35 objects, then copy-on-write saved 65% > of the maximum amount of work (eg. if you deep-copied every > one of the 100 objects that would 100% work). these issues > are consisently *NOT* talked about in eiffel literature. > > shane miller > geferan systems This is a good question. A solution is not completely obvious. What I have done is: - add mark_for_store and marked_for_store features to a class from which all storable business objects must inherit. Note that with ISE's EiffelStore, only the root object of a logical "business" object has to do this inheritance, e.g. you might have PERSON, with all kinds of bits and pieces e.g. ADDRESS, PERSON_NAME, etc, etc. Only PERSON need inherit from the storable ancestor. - when you call modifier routines, they have to set mark_for_store to True. This sounds tedious, but in reality I have not found it a problem. Again this only relates to business objects, not the bits and pieces. As an overall approach, I have come up with the following, for complex objects. 0. It is essential to understand the difference between a business (or "domain") object such as PERSON, VEHICLE, NET_NODE etc, and the actual network of instances which will make up any of these objects. When you are talking about storing "objects" you have to actually think about networks of instances, right down to the LINKABLE instances making up a LINKED_LIST. 1. I call a business or domain object a "composition" of instances. A composition is the smallest unit that can be read from or written to the database, since modifications and reading require the whole logical object. 2. Complex business objects (investments, vehicles, SCADA control systems) tend to be "parts explosions" of informational business objects. E.g. VEHICLE might be a business object containing ENGINE and GEAR_TRAIN, each of which is also a business object. I use the word "aggregation" to mean aggregation of business objects. A "sub-aggregation" is a partial "tree" from an intermediate point down. This is very useful where the aggregations are trees of software objects in a CM system for example; a sub-aggregation could correspond to a component, a subsystem, a project etc. 3. Now you are in a position to attach sensible semantics to the read and write of a) compositions, aggregations (of compositions), and sub-aggregations. Semantics include granularity of modification, locking, version control and so on. A typical example would be to enforce locking of entire sub-aggregations when a modification was requested. 4. Once these basics are in place, you can implement intelligent storage schemes. For example, if a business object composition is altered, write the whole thing. You can't do otherwise - think about what happens at the instance level if the contents of PERSON.addresses: LINKED_LIST[ADDRESS] changes. Mark-for_store can be implemented on a per-composition basis. Now it can be seen that if an object like INVESTMENT has a LIST of PORTFOLIO, and both INVESTMENT and PORTFOLIO are programmed as business objects, a write on INVESTMENT will traverse into all PORTFOLIO objects, writing only those marked-for-store. This type of approach gets out of mindlessly traversing entire networks of objects connected by reachability. You rarely want to do that. Instead, you want to traverse business objects and aggregations, and stop when you hit a new aggregation, and simply update association references to it. The aggregation relationship (as described above) is the relationship type which determines the scope of traversals for writing and reading. Another area of complexity is business object validity. When is a PERSON valid; particularly, while constructing a PERSON object from its parts, when is it ok to call it valid? Simple Eiffel invariants for valdity don't work, since many operations may be needed on an object before it is fully built (e.g. if consturcting it from RDBMS records). When the composition is viewed as the unit of construction, compositions are also the place to put basic validity functions, as well as a marker of some kind saying when an object has been built for the first time, and it is now sensible to call my_obj.is_valid. Obviously there are many details to a scheme like this, but these are the essentials. One last note: how do you decide what is a business object and what is not? Does an ADDRESS need to be a business object? My answer is: only if its existence is meaningful on its own. If you want a repository of ADDRESS objects, then yes; if ADDRESS will only ever mean anything when building PERSON objects, then no. - thomas beale