|
From: Jeremy F. <jfi...@ma...> - 2002-10-29 22:51:37
|
Thought this thread might be of interest to others on the list. Nathan =
and I have been talking about a couple of issues I've raised, namely, =
contentObjects containing collections of other contentObjects and the =
performance impact of instantiating so many objects.
Note that this reads from the bottom up:
Nathan - certainly not wed to the interface. But unless, as you suggest, =
the definition of what a field is changes I don't see a way of using =
basefield for content objects. Back to the forum example I've been using =
- retrieving a collection of threads:
The way I suggested:
<cfset forum=3D createObject("component","forum").init(forumID)>
<cfset threads=3D category.getObjectArray('threads')>
<cfloop from=3D"1" to=3D"#arrayLen(thread)#" index=3D"i">
<!--- doing stuff with each thread, like: --->
#thread[i].getField('thread').getValue()#=20
</cfloop>
One possible way of doing what you suggest:
<cfset forum=3D createObject("component","forum").init(forumID)>
<cfset threads=3D category.getField('threads').getValue()>
<cfloop from=3D"1" to=3D"#arrayLen(thread)#" index=3D"i">
#thread[i].getField('thread').getValue()#
</cfloop>
As you can see the only difference is the method call for the threads =
array. And of course this gets back to the descriptor for the content =
object. In the first case thread would have a property type of =
'objectArray' or 'subcomponent' or something like that, and in the =
latter it has the type 'field' with a particular fieldType.=20
If the latter seems cleaner to you, fine. I just did it this way to =
avoid reworking basefield - sort of a proof of concept. The developer =
using the API already needs to know the 'type' for various fields. Most =
are simple strings, but anything that extends basefile will certainly be =
handled differently, or at least make several new methods available. So =
making 'contentObject' be a possible fieldType should be doable - the =
basefieldValue idea is probably the way to go. Let me think about that a =
bit.
As for the performance issue, it comes in precisely when you want to =
instantiate a whole array of contentObjects. If I call load() on a 40 =
page book object, a new instance has to be created for each of these =
pages. The only way to avoid that is to reference the cached object, =
which opens up a whole other can of worms - locking the server scope, =
concurrent access to writable data... This may be possible, but is this =
a route worth going down. Maybe others have thoughts.
- Jeremy
----- Original Message -----=20
From: Nathan Dintenfass=20
To: Jeremy Firsenbaum=20
Sent: Tuesday, October 29, 2002 12:27 PM
Subject: RE:=20
Ah, I see what you mean. Yes, get() does that, but only if you wish =
to populate from another instance -- which you pass in -- that is, if =
you have an existing contentObject that you want to "load()", then you =
need to do this. But, in this case you still never need to recreate a =
whole new instance as you already have the one you want to load and the =
one you retrieve from the cache (except on the first hit) -- but, what =
you are saying is that is a performance bottleneck for you, right? Hmm.
On the "interface" I was talking about -- yes, the API exposed to the =
end user. I figured you were not wed to it. My instinct says that it =
would be better to do an overhaul of what a "field" is. First, I'd make =
it possible to have an array of values, even if not other contentObject. =
Then, I'd work on making it possible to have the value of a field be a =
contentObject. Perhaps baseFieldValue.cfc would be one way to get =
towards that??
I totally agree that one way or another there needs to be a way to =
have a "book" and its "pages" (not to mention many-to-many =
relationships) and have "book" and "page" each be instances of a =
contentObject.
- Nathan
-----Original Message-----
From: Jeremy Firsenbaum [mailto:jfi...@ma...]
Sent: Monday, October 28, 2002 5:33 PM
To: na...@ch...
Subject: Re:=20
"By the way, the only place I am using the makeClone() is when I put =
objects into the cache, not when I take them out of the cache"
I'm sorry if I was misleading. "Cloning" takes place going in as =
well as coming out, although the makeClone method is only called one =
way. Going in, makeclone calls contentObjectPopulateFromInstance, which =
does all of the actually duplicating. Coming out, get() calls =
contentObjectPopulateFromInstance as well:
line 41 from simplefilesystempersister.cfc:
if(instance.cache.isObjectCached(arguments.id)){
objectRetrieved =3D instance.cache.getObject(arguments.id);
if(structCount(arguments) GT 1)
return =
contentObjectPopulateFromInstance(arguments[2],objectRetrieved);
else
return objectRetrieved;=20
}
I found the duplicating from a cached instance in =
contentObjectPopulateFromInstance to be the bottleneck.
"I'm not sure I'm personally satisfied with the interface you are =
using in your forums app."
I'm all up for criticism - but not sure what you're referring to by =
interface. Do you mean the contentObjectArray within basecontentobject, =
or the way in which the API is used externally to construct the forum. =
Obviously this was just an example I was using to work with the idea of =
content objects within content objects.
"Are you waiting for a signal from me as to what my alternative =
might be?"
Well - kinda, yeah. I mean I would like to know if this approach to =
"composition" even makes sense, or whether there's another way of doing =
"parts of" relationships within modus. Many systems, content management =
or otherwise, have this kind of structure. An artifact, say a book, has =
many pages, each one of which has been scanned in. At one level, you =
want to deal with the book as a whole (when presenting a library of =
books), on another level, each one of the pages is a content object unto =
itself (so that the book is browsable). I would like to be able to load =
the book, for a single request or in session scope, and have the pages =
come along for the ride, just as each thread is available within the =
forum content object. Does this even make sense within the context of =
what modus was and is being designed to do?
----- Original Message -----=20
From: Nathan Dintenfass=20
To: Jeremy Firsenbaum=20
Sent: Monday, October 28, 2002 7:56 PM
Subject: RE:=20
Ah, yes. Well, right now you are at the cutting edge of that =
question. I'm not sure I'm personally satisfied with the interface you =
are using in your forums app. Doesn't feel clean to me, but I have a =
hard time justifying that feeling. Are you waiting for a signal from me =
as to what my alternative might be?
By the way, the only place I am using the makeClone() is when I =
put objects into the cache, not when I take them out of the cache -- are =
you experiencing serious performance problems with that? My main issue =
with performance before the caching was with the getAll(). Load() is =
still a bit slower than I'd like, but I figure that will be rarely =
called in volume since getAll would be generally be faster. That is an =
area to work on, though.
- n
-----Original Message-----
From: Jeremy Firsenbaum [mailto:jfi...@ma...]
Sent: Monday, October 28, 2002 4:45 PM
To: na...@ch...
Subject: Re:=20
Sorry for being obtuse - I mean being able to declare other =
content objects as being contained within another content object: forums =
are composed of threads, which are composed of posts...
----- Original Message -----=20
From: Nathan Dintenfass=20
To: Jeremy Firsenbaum=20
Sent: Monday, October 28, 2002 7:37 PM
Subject: RE:=20
When you say "composition of content object" what do you mean?
- n
-----Original Message-----
From: Jeremy Firsenbaum [mailto:jfi...@ma...]
Sent: Monday, October 28, 2002 4:33 PM
To: na...@ch...
Subject: Re:=20
Fair enough. Maybe it's all of the nested subcomponents that =
accounts for the slowness in cloning from the cache.
I'd love to do some more work on modus, maybe sink my teeth =
in the XML descriptor thing, but I feel like I can't do much with it =
until I know whether composition of content objects is feasible. This =
seems to be the most important feature needed to model more complex =
systems. Looking forward to seeing what you think.=20
-Jeremy
----- Original Message -----=20
From: Nathan Dintenfass=20
To: Jeremy Firsenbaum=20
Sent: Monday, October 28, 2002 7:13 PM
Subject: RE:=20
Jeremy:
I hadn't yet gotten to look in depth at your changes. I =
agree the clone() method is far from optimal (as I mentioned in that =
posting).
My comment was based on the dramatic performance =
enhancement I witnessed on the modustest app after implementing the =
caching. My calls to getAll() went from over 400ms with a handful of =
"press releases" to 20ms.
- n
-----Original Message-----
From: Jeremy Firsenbaum [mailto:jfi...@ma...]
Sent: Monday, October 28, 2002 3:52 PM
To: Nathan Dintenfass
Subject:=20
Hey Nathan
I saw your post to CFCDev today:
"I have taken pages that were slow because they had to =
instantiate dozens of components and made them very fast by just =
grabbing from the cache in the server scope."
This got me wondering if you have looked into the =
performance issue with clone() that I mentioned last week. It seems like =
it wouldn't make a difference whether the subcomponents were =
instantiated within the contentObject, as I had tried to do, or if this =
were left to the developer to do externally: forums =3D createObject =
(forum.cfc), loop for threads =3D createObject(thread.cfc). If you need =
"dozens of components" the clone technique doesn't seem to be optimal.
Were my performance numbers similar to yours (if you've =
had time to look into this) or am I totally off base here?
Jeremy
|