Board index » delphi » Re: Are your persitable objects crudy?

Re: Are your persitable objects crudy?


2004-06-02 11:11:29 PM
delphi170
"Bob Dawson" <XXXX@XXXXX.COM>a écrit dans le message de news:
40bdd947$XXXX@XXXXX.COM...
Quote
I'd say rather than opinion is mixed (but feeling lonesome at the moment).
Well if you will duck out of the OPF BoF session on the pretext of going on
vacation to a whiskey distillery... :-))
Joanna
Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker
 
 

Re: Are your persitable objects crudy?

"Bob Dawson" wrote
Quote

In addition to these two OO design objections, I have a third, more usage
oriented: If the BO doesn't have to communicate with the OPF, then you've
just pushed that responsiblity to the application writer, who already has
enough to do--isn't a major point of the OPF to simplify app code? Why
make
an application writer pass objects to a framework that he/she shouldn't
really have to worry about at all? The OPF should just be there and work,
without app programmer intervention. The syntax
myBO.Save
expresses application intent perfectly and succinctly.
I agree that it does make it easier for the app developer but it makes it
almost too easy in my eyes. If they have to write
Broker.StoreObject(SomeObject) then they are going to have to think about
what that Broker object is and more importantly, have they initialized it
yet with the proper Connection object (username, password, connect string)
and is it connected? I feel even the app developer needs to be aware of the
different levels going on in their application.
Perhaps my need to create an OPF for legacy tiers has corrupted my wee nut
but it is been nice being able to Load from one persistance mechanism to Save
to another, without having to swap out Connection objects. I simply have
two PersistanceBrokers to work with.
Slainte mhath,
Shawn Oster
 

Re: Are your persitable objects crudy?

"Joanna Carter (TeamB)" writes:
Quote
2. Write one persister or adapter class per BO class, where you are
dealing
with legacy classes that cannot be modified..
Yup, that is where I am at. One adapter that supports Store\Retrieve\Delete
(as I am just rolling up Add\Update into Store).
Quote
The only other concession has to be some means of including the concept of
object ID in any class that has to support persistence, but even this can
be
kept outside of the knowledge of the BOs.
The objects I am forced to work with luckily have ID's in them already.
Granted they are the actual primary key IDs from the database but they are
working rather well for this project. I came across something you mentioned
in one of your old articles about the lack of a friend qualifier in Delphi.
I can really see how that would be useful for the ID. I dislike that the ID
is read/write but then again without a friend qualifier there really is no
other way to handle setting the ID of a new object.
Shawn Oster
 

Re: Are your persitable objects crudy?

"Hechicero" writes:
Quote

Another subject. If we keep talking about best designs, I wouldnt have a
Broker.SaveObject. I'd support transactions. The OPF I am using right
now works something like this...

Client1 := FrameworkFactory.CreateNewClient;
Address1 := FrameworkFactory.RecoverAddress('Hills Avenue 1980');
Client1.Name := 'John Doe'
Client.Address := Addess1;
HecPersistence.Commit;
I'm trying to see where the transaction starts in this. Also how does the
framework factory link with the HecPersistence object? I agree transactions
are very important. Right now I am handling those at just the database
level. Each SaveObject method I have starts and commits a transaction on my
Connection object. Any contained objects simply bump up the Transaction
count and when it reaches 0 I do the actual physical commit on the database.
Rough but it works.
Shawn Oster
 

Re: Are your persitable objects crudy?

"Bob Dawson" writes:
Quote

1. it is the BO itself (or some interface it supports) that gets passed to
the persistence layer. that is an unnecessary design constraint, as
demonstrated by the above. Even Joanna's attribute framework approach
could
be implemented as
Broker.SaveObject(self.FRoutingInformation, self.FAttributes);
end;
resulting in a persistence layer with no concept of BOs at all.
At which point I assume you do all your mapping on the PersistencePacket
instead of the actual buisness object? Since you are going for a
persistence layer (PL) with no BO concept, and the mapping layer is owned by
the PL you must be mapping it directly to the meta-data? It'd be
interesting to see all those pieces working together in a small example. I
like the concept.
Quote
2. it is possible, once passage to the persistence layer has taken place,
for
that layer to inspect/deconstruct the BO externally (either via RTTI or
some
other mechanism). that is a containment violation, in that if the
persistence
layer can do it, so can the GUI; interfaces cannot be declared as private
and passed to selected partners only.
So far I haven't had to worry about getting at any information that isn't
already publicly available via properties. In fact I have been wondering just
what private data people are needing to get at via RTTI/reflection. Of
course I am just dealing with client information, addresses, phone numbers,
status codes, etc.
Sorry for the double response on this, I am the type of bloke that reads
magazines backwards and I tend to reply that way as well. Got over eager
and hit sent *grin*.
Shawn Oster
 

Re: Are your persitable objects crudy?

"Shawn Oster" wrote
Quote
almost too easy in my eyes. If they have to write
Broker.StoreObject(SomeObject) then they are going to have to think
about what that Broker object is [...]
'Having to think about it' all the time == 'cut and paste, or get a good
chance to get it wrong'
You can make a choice available without losing default behavior. IOW, your
case of
Quote
Load from one persistance mechanism to Save
to another, without having to swap out Connection objects.
can be accomplished fairly easily with optional parameters or methods--
myObj.Save;
will route to the normal data provider for that class, but
myObj.Save('Alt_Named_dbRole');
or
myObj.SaveTo('Alt_Named_dbRole');
allows redirection under programmer control. You can build the persistence
layer to accomodate an array of persistence handlers without forcing the
user to juggle them manually. IMO app programmer intervention in persistence
routing should be an exceptional need, not a standing requirement.
bobD
 

Re: Are your persitable objects crudy?

"Shawn Oster">
Quote
At which point I assume you do all your mapping on the
PersistencePacket instead of the actual business object?
Right--BOs forward two things to the persistence layer:
an IPLIdentifiable interface, which contains identifying and routing
information, and IPLPersistable, which acts somewhat like Joanna's attribute
collection in being able to support a run-time discoverable array of
properties/values.
the broker object in the line
broker.SaveObject(Identifier, Persistable)
is really a broker, not a persistence handler--it evaluates the Identifier
package and routes the call to the appropriate connection.
Quote
So far I haven't had to worry about getting at any information that isn't
already publicly available via properties. In fact I have been wondering
just what private data people are needing to get at via RTTI/reflection.
Public interface of a class may not include all pertinent state data, and
complex objects may have property interactions or other behavior programmed
into property getters/setters that you don't want a db load to hit. For
example,
--in order to assume mfg state 6, a product must be in state 5
--on any processing state change, an object must spawn a 'process complete'
record for the previous state.
--additionally on entry to state 6, an object will spawn a process 6 queuing
item
--process change events are accumulated by the object and saved whenever the
item saves
How does the db load a process 6 item if it has to go through this logic?
Quote
course I am just dealing with client information, addresses, phone
numbers, status codes, etc.
Suppose that any address change has to be recorded, so that you can
reconstruct AddressAsOf(datetime) for any customer.
bobD
 

Re: Are your persitable objects crudy?

On Wed, 2 Jun 2004 08:38:23 -0500, Bob Dawson writes:
Quote
<Aside>
Actually I did see a framework design that included 'aBO.Edit'. Such a call
routed to a GUI broker, which passed the BO in turn to whatever form or
frame was currently registered as its editor--much like being routed to a
persistence handler. IIRC, the method was defined as a boolean, returning
true if the object had been changed during the edit method.
</Aside>
I think that this would warrant a UI Manager just as we have a
Persistence Manage.
Quote

In addition to these two OO design objections, I have a third, more usage
oriented: If the BO doesn't have to communicate with the OPF, then you've
just pushed that responsiblity to the application writer, who already has
enough to do--isn't a major point of the OPF to simplify app code? Why make
an application writer pass objects to a framework that he/she shouldn't
really have to worry about at all? The OPF should just be there and work,
without app programmer intervention. The syntax
myBO.Save
I think that Using BO.Save makes it difficult to handle multiple
persistence mechanisms or dynamically choosing the persistence
mechanism.
It also means that your BO objects have to implement non-business code
and are more tightly coupled to the business layer. After Save and
Load would you add Refresh, Delete. Where do you stop. BO.Edit,
BO.SendByMail, BO.Print?
Marc Rohloff
marc rohloff at myrealbox dot com
 

Re: Are your persitable objects crudy?

In article <40bd68fb$XXXX@XXXXX.COM>, monocularjack@change-
haute-to-hot.hautemail.c0m says...
Hi,
Quote
ACustomer.Save

Just seems really weird and vague. While doing the following:

Broker.SaveObject(ACustomer)

is more clear.
..it does to me as well.
Phil
--
Discover a lost art - play Marbles
May 2004
www.marillion.com
 

Re: Are your persitable objects crudy?

"Joanna Carter (TeamB)" wrote
Quote

Well if you will duck out of the OPF BoF session on the pretext of going
on
vacation to a whiskey distillery... :-))
Don't think of it as ducking out; think of it as trusting to your reports
:-)
bobD
 

Re: Are your persitable objects crudy?

Bob Dawson writes:
Quote
"Bob Dawson" wrote
>Since BO.Save could (but needn't) implement
>Broker.saveObject()
>internally, how is such a limitation encountered?

Put another way, I regard the question of having a
Bobject.save;
method as really a question of how persistence will be surfaced to
the app developer, not as a question of how persistence is
implemented. I find it a convenient and natural surfacing, even
though my BOs are ignorant of the OPF's actual implementation details.
The method call:
BO.Save;
...is a convenient one, no doubt. But - it introduces a coupling that one
doesn't need. Coupling is the enemy of reuse, IMHO.
Do we need "Business Object" as a term in the OPF ? No, not really. The BO
is a BO because it may a) be stored and retrieved, and b) Be used with
controls, reports, etc.. The fact that it represents something related to
the user's business rather than some internal technical mumbo-jumbo isn't
really important. What *is* important is that the object is part of a data
structure that is the *User data*, distinguished from various kinds of
system data, user settings, etc..
It may also be convenient to distinguish between "Register data" and "User
data", where ZIP codes & Customer tables may be an example of the first,
while Invoice data belongs to the latter. It doesn't *need* to be organized
that way, but it may be convenient to some applications. And typically, if
there is differences between the handling of "Zip codes" and "Invoice
lines", it is about their place in the implementation model more than whether
they classify as "Business Objects" or not. The exception to this is
possibly the validation part. This has to do with the object being editable
or notrather than having anything to do with "business".
At application level (hence, controlled by user actions) one decides the
storage parameters; selecting a database, choosing a filename, etc.. To make
the BO.Save; work, one must set the properties of the persistence layer so
that the 'Save' method gives the desired result. This is of course possible,
but the model isn't all that obvious. One may want to do a whole lot of
different things with modified data, and a lot of rules and options may
exist. It leads to an extremely stateful application, with a lot of
"indirect" logic.
IMHO, what you *do* need to "bury in a black box" is the following:
- Coupling between editors/controls and edited object.
- Storage of object into desired media. That is, there may be special cases
where you need to write the entire storage stuff for just one application's
sake.
...even a plain thing like the 'New Object' functionality may involve a lot
of specialized stuff, and one doesn't necessarily want to bury this down in
the OPF.
The control question could be: "When do you write a call to BO.Save; ?" - it
will IMHO lead to the answer: "Hardly ever." This is more typically an
indirectly invoked operation. E.g. when a grid line looses focus, or a modal
editor window is closed. Rather, it is some kind of available event -
"Object editing finished" - that the OPF needs to route somewhere. I don't
want to pepper my code with 'BO.Save;', I want another kind of coupling
between controls/BO/storage. And - I have seen that it is as important to
leave flexible the things that typically change between applications, as
important as having implemented all that is general.
--
Regards,
Bjørge Sæther
XXXX@XXXXX.COM
-------------------------------------
I'll not spend any money on American Software products
until armed forces are out of Iraq.
 

Re: Are your persitable objects crudy?

"Marc Rohloff" wrote
Quote
I think that this would warrant a UI Manager just as we have
a Persistence Manage.
Fairly similar--forms registered themselves with the GUI system just as
custom persistence handlers might. The UI or view manager (I have no memory
of what they called it) considered both requesting BO type and security
context in choosing the appropriate editor to return.
bobD
 

Re: Are your persitable objects crudy?

"Bjørge Sæther" wrote
Quote
...is a convenient one, no doubt. But - it introduces a coupling that
one doesn't need. Coupling is the enemy of reuse, IMHO.
Granted, but the coupling isn't really that tight, and to a certain extent
is inevitable anyway. The BO class needs only a reference to an OPFServices
interface--not a class level coupling. And can anyone claim that their OPF
makes no demands whatsoever on what it understands? My OPF requires that
objects to be saved be able to produce a specific IPLPersistable
interface--but they needn't implement it personally. Since taking any
arbitrary object and inroducing it to the system would at minimum mean
introducing an adapter that could accomodate this, it seems a small addition
to make that adapter into a wrapper class that supports a Save call.
I'm not arguing that one _has_ to provide direct persistence methods on
persistable objects, just that it is convenient, preserves OO class
containment, appears 'natural' for a user, and with a bit of work can be
just as flexible as forcing the app programmer to submit the object the
framework manually.
Quote
The control question could be: "When do you write a call to
BO.Save; ?" - it will IMHO lead to the answer: "Hardly ever."
This is more typically an indirectly invoked operation.
Actually this is a substantial philosophical difference. My answer is "The
OPF has no independent authority to save anything; 'Save' is invoked in
application logic, usually if not always in response to direct user
gesture." Unless the application programmer writes .Save, it doesn't happen.
The only qualification to this is that objects may own collections of
objects, so for example the line
Order.Save
will save the Order object, any dirty LineItem objects owned by the order,
etc. Put another way, saves are atomic over object sub-hierarchies.
bobD
 

Re: Are your persitable objects crudy?

"Bob Dawson" <XXXX@XXXXX.COM>a écrit dans le message de news:
XXXX@XXXXX.COM...
Quote
Since taking any
arbitrary object and inroducing it to the system would at minimum mean
introducing an adapter that could accomodate this, it seems a small
addition to make that adapter into a wrapper class that supports a Save
call.
Can you share a rough idea of your Adapter design?
Quote
Actually this is a substantial philosophical difference. My answer is "The
OPF has no independent authority to save anything; 'Save' is invoked in
application logic, usually if not always in response to direct user
gesture." Unless the application programmer writes .Save, it doesn't
happen.
I would agree that the OPF has no independent authority to save anything,
but surely the BO should not know that it can be saved either? Therefore the
only way of invoking a 'save' is for the application code to link the two
together and perform the required action.
Since developing my MVP framework further, I now use the Model to look after
the CRUD of objects :
/////////////////////
TOrderModel = class(...)
class procedure Store(order: IOrder);
...
end;
class procedure TOrderModel.Store(order: IOrder);
var
tx: ITransaction;
cust: ICustomer;
lineIter: IOrderLineIterator
product: IProduct;
begin
tx := TTransaction.Create;
try
tx.AddStoreObject(order); // this also adds internal lines to tx
cust := order.Customer;
cust.TotalOnOrder := cust.TotalOnOrder + order.Total;
tx.AddStoreObject(cust);
lineIter := order.Lines.GetIterator;
while lineIter.Next do
if lineIter.CurrentItem.IsDirty then
begin
product := lineIter.CurrentItem.Product;
product.QtyReserved := product.QtyReserved +
lineIter.CurrentItem.Qty;
tx.AddStoreObject(product);
end;
tx.Commit;
except
tx.Rollback;
end;
end;
...this then gets called by a Command in an instance of the Model :
procedure TStoreOrderCommand.Execute;
var
iter: ISelectionIterator;
begin
iter := GetCurrentSelection.GetIterator;
while iter.Next do
TOrderModel.Store(iter.CurrentItem as IOrder);
end;
//////////////////////////
This ensures that not only is each Order stored inside a transaction, but
the related Customer and Products are also included in the same atomic
transaction.
Quote
The only qualification to this is that objects may own collections of
objects, so for example the line
Order.Save
will save the Order object, any dirty LineItem objects owned by the order,
etc. Put another way, saves are atomic over object sub-hierarchies.
Agreed
Joanna
Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker
 

Re: Are your persitable objects crudy?

"Bjørge Sæther" <XXXX@XXXXX.COM>a écrit dans le message de news:
40beff49$XXXX@XXXXX.COM...
I could not divide your message to reply easily to a section, so here are
some thoughts related to your message (vaguely) :-))
In this group we seem to do a lot of discussing about whether the BO should
know about persistence and vice-versa.
I have just started to look at porting my OPF to C#, which has caused me to
think very carefully at how much of the Delphi baggege I need to take with
me.
C# supports the concepts of reflection and serialization.
Therefore, if all classes can be inspected for their field values, we do not
strictly need the Value (Attribute) framework we had in Delphi to give us
this introspection, either for persistence or display.
What is becoming clear though is that we still have to mark all fields that
are persistable in some manner to stop us persisting fields that are only
used for temporary working storage.
Now we could dream up our own PersistableAttribute class that would allow us
to mark fields as persistable, but if we use the SerializableAttribute
already provide, then by marking temporary storage fields as
NonSerializable, we have a ready made mechanism for serializing objects.
Could we, in theory, write a custom .NET formatter that knows how to create
SQL scripts and get the application code to simply serialize the object to
the OPF or remote machine/process etc??
Because reflection/serialization is an expected part of any object,
especially if we are using remoting, is this implementation hiding still
such a big issue?
What is more, we could also add attributes that define things like string
length or decimal precision on each field.
String length has always felt like a DB imposed limit and I still need
convincing as to the best place to impose this limit as it also affects
imput and validation.
Decimal precision, IMO, is an important metadata item that rightly belongs
in the BO class.
Joanna
Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker