You can subscribe to this list here.
2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(72) |
Oct
(15) |
Nov
(68) |
Dec
(1) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2003 |
Jan
(9) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Nathan D. <na...@ch...> - 2002-11-14 20:59:49
|
Yes, exactly. A facade is not a User Interface. Thus, things that are for outputting to a user interface should not be called a facade ;) The issue with custom tags is that they don't have access to the scope of the calling page (absent the very ugly "caller." syntax). My point is that if we just have something in Application.cfm that sets something as a local var called "modus" then a custom tag will still have to use the server.modus or request.modus or application.modus construct -- I'm trying to keep the code inside my custom tags looking the same as the code outside my custom tags. I'd rather not use application.modus because many applications don't use the CFAPPLICATION tag. Given that we're moving to "Modus as service" as our model, server.modus makes the most sense to me (why copy it all into the request scope, after all?). Make sense? - n -----Original Message----- From: mod...@li... [mailto:mod...@li...]On Behalf Of Sean A Corfield Sent: Thursday, November 14, 2002 12:53 PM To: mod...@li... Subject: Re: [Modus-devs] Re: New Code Posted On Thursday, Nov 14, 2002, at 11:56 US/Pacific, Jeremy Firsenbaum wrote: I do think the term "facade" is not particularly friendly. I could even see it being simple "ui" -- a term that is both well known and very descriptive. But a facade is not a User Interface! > No problemo - this was Sean's suggestion so I thought I'd try it. > The UDFs are really just directing traffic to the appropriate > facade. This could also be implemented as a cfc. This way a > Application.cfm could have something like: > > modus = server.modus.udflib > > so the calls would be: modus.get(id) and modus.put(object). That's sufficiently elegant for my tastes. I'm just trying to suggest ways to reduce the amount of (unnecessary) typing people have to do. Yeah, I figured this was more proof-of-concept than it was API proposal. My issue is that it would be great if the developer types the same thing inside a custom tag as they do outside a custom tag. That would require something like server.modus.get() or request.modus.get() every time, though. I don't understand why custom tags makes a difference - could you explain? |
From: Sean A C. <se...@co...> - 2002-11-14 20:53:09
|
On Thursday, Nov 14, 2002, at 11:56 US/Pacific, Jeremy Firsenbaum wrote: > I do think the term "facade" is not particularly friendly.=A0 I could=20= > even see > it being simple "ui" -- a term that is both well known and very=20 > descriptive. But a facade is not a User Interface! > > No problemo - this was Sean's suggestion so I thought I'd try it. > > The UDFs are really just directing traffic to the appropriate > > facade. This could also be implemented as a cfc. This way a > > Application.cfm could have something like: > > > >=A0=A0=A0=A0=A0 modus =3D server.modus.udflib > > > > so the calls would be: modus.get(id) and modus.put(object). That's sufficiently elegant for my tastes. I'm just trying to suggest=20 ways to reduce the amount of (unnecessary) typing people have to do. > Yeah, I figured this was more proof-of-concept than it was API=20 > proposal.=A0 My > issue is that it would be great if the developer types the same thing=20= > inside > a custom tag as they do outside a custom tag.=A0 That would require=20 > something > like server.modus.get() or request.modus.get() every time, though. I don't understand why custom tags makes a difference - could you=20 explain? "I have always wished that my computer would be as easy to use as my telephone. My wish has come true - I no longer know how to use my telephone." -- Bjarne Stroustrup |
From: Jeremy F. <jfi...@ma...> - 2002-11-14 19:57:06
|
This is the beginnings of a conversation between Nathan and I about the = revamped Modus code I posted on Sunday. Thought it would be appropriate = to share: > I'm in the middle of rethinking this now. I want the ability to > define contentObject-level components, especially persisters. > But, the facade, validator and renderer are more > application-level. I'm thinking of renaming the facade to > contentobject and define these in the global settings file - that > way the true interface for the developer would be the > contentObject. The descriptors would then define content types > that the contentobjects can implement. So you could have a > pressrelease, a remotingPressrelease and a xmlPressrelease using > the same descriptor. This is all in progress so more to come. The > end goal, of course, is a blend of simplicity and flexibility. A > newbie should be able to edit the example app and have a running = website. I absolutely agree about the newbie case. I think it would also be = good if we keep things at the contentObject level rather than the application = level. That is, using different contentObjects with different = validators/renderers in a single application makes some sense to me. My question was more = about the semantics of: <components> <component name=3D"persister" type=3D"org.bacfug.modus.persistence.simpleobjectinstance" /> <component name=3D"validator" = type=3D"org.bacfug.modus.validation.validator" /> <component name=3D"renderer" = type=3D"org.bacfug.modus.rendering.baserenderer" /> <component name=3D"facade" = type=3D"org.bacfug.modus.facades.webfacade" /> </components> As opposed, perhaps to: <persister type=3D"..."/> <validator type=3D"..."/> In fact I started this way, naming the components. However, I was = looking for a way to add new component types without altering the = registry code. In the end, I don't know if this will possible, but it's = a nice ideal. Just write a new component, add it to the settings file = and away we go. In any case, I'm reworking the whole descriptor = implementation so I'll keep you updated. I do think the term "facade" is not particularly friendly. I could = even see it being simple "ui" -- a term that is both well known and very = descriptive. > > 2) I am not fully comfortable with the UDF lib as is. It creates > issues with using custom tags, so I would prefer to see some kind > of convention like server.modus.get(), or some other way that a) > makes the code the same inside a custom tag as outside a custom > tag and b) makes the API a developer uses more explicitly in a > Modus "namespace" of sorts. > > No problemo - this was Sean's suggestion so I thought I'd try it. > The UDFs are really just directing traffic to the appropriate > facade. This could also be implemented as a cfc. This way a > Application.cfm could have something like: > > modus =3D server.modus.udflib > > so the calls would be: modus.get(id) and modus.put(object). > > Lot's of ways of doing this so when you guys get some time to dig > in we can figure out the best way. Yeah, I figured this was more proof-of-concept than it was API = proposal. My issue is that it would be great if the developer types the same thing = inside a custom tag as they do outside a custom tag. That would require = something like server.modus.get() or request.modus.get() every time, though. I suppose it's not crucial that it's always the same, but it would be = nice if Modus code always looks like Modus code, if you get my drift. Absolutely - it would be silly to have a split API depending upon scope = - I also think CFC methods don't see UDFs. BTW, your speed numbers are very convincing! -Jeremy |
From: Sean A C. <se...@co...> - 2002-11-14 03:33:33
|
On Friday, Nov 8, 2002, at 10:46 US/Pacific, Jeremy Firsenbaum wrote: > Ok Sean - you've got me cracking up on this one.=A0 I've been doing=20 > fusebox for so long (one gets stuck in a conceptual as well as=20 > technical framework), and Application.cfm is basically off limits=A0for=20= > fusebox=A0"best practices." Wow, I'm blushing over having forgotten = that=20 > one. Having just rebuilt my personal site using FB3 for PHP I can sympathize=20= - I had quite a mental shift to get into Fusebox and I've found as I've=20= explained it to some of my less technical colleagues (e.g., designers)=20= they've gotten really excited and I've gotten to like Fusebox more than=20= my public comments would lead anyone to believe... I'm pretty excited about Hal's new baby - Fusebox MX - which addresses=20= many of the criticisms I've leveled at FB3. But I digress. > <cfset server.modus.registry.register(application.hardroot & > "descriptors/pressrelease.xml")/> > =A0 > Yes - I addressed this in a later email yesterday - but (see below)=20 > this won't even be necessary. Nice. Yes, I hadn't gotten far enough through the thought process to=20 make that jump and it makes a lot of sense (especially now I have more=20= exposure to Fusebox, with it's fbx_Circuits file which will become=20 fbx_circuits.xml in Fusebox MX!). "I can smell your brains!" -- Mittens the Kitten : http://www.matazone.co.uk/theotherside.html |
From: Sean A C. <se...@co...> - 2002-11-14 03:33:15
|
On Friday, Nov 8, 2002, at 10:46 US/Pacific, Jeremy Firsenbaum wrote: > Ok Sean - you've got me cracking up on this one.=A0 I've been doing=20 > fusebox for so long (one gets stuck in a conceptual as well as=20 > technical framework), and Application.cfm is basically off limits=A0for=20= > fusebox=A0"best practices." Wow, I'm blushing over having forgotten = that=20 > one. Having just rebuilt my personal site using FB3 for PHP I can sympathize=20= - I had quite a mental shift to get into Fusebox and I've found as I've=20= explained it to some of my less technical colleagues (e.g., designers)=20= they've gotten really excited and I've gotten to like Fusebox more than=20= my public comments would lead anyone to believe... I'm pretty excited about Hal's new baby - Fusebox MX - which addresses=20= many of the criticisms I've leveled at FB3. But I digress. > <cfset server.modus.registry.register(application.hardroot & > "descriptors/pressrelease.xml")/> > =A0 > Yes - I addressed this in a later email yesterday - but (see below)=20 > this won't even be necessary. Nice. Yes, I hadn't gotten far enough through the thought process to=20 make that jump and it makes a lot of sense (especially now I have more=20= exposure to Fusebox, with it's fbx_Circuits file which will become=20 fbx_circuits.xml in Fusebox MX!). "I can smell your brains!" -- Mittens the Kitten : http://www.matazone.co.uk/theotherside.html |
From: Jeremy F. <jfi...@ma...> - 2002-11-08 18:46:37
|
On Thursday, Nov 7, 2002, at 14:22 US/Pacific, Jeremy Firsenbaum = wrote: > The attached file starts with an include of initModus.cfm. This file = > is responsible for setting the framework up and so must be included = on=20 > every request. I would hope that most developers are using a=20 > methodology that can accomodate global includes. It's simple with=20 > fusebox - you just add it to fbx_settings, but a looser set up=20 > would need to do it some other way. What, like Application.cfm? :) Ok Sean - you've got me cracking up on this one. I've been doing = fusebox for so long (one gets stuck in a conceptual as well as technical = framework), and Application.cfm is basically off limits for fusebox = "best practices." Wow, I'm blushing over having forgotten that one. Why not just: <cfset server.modus.registry.register(application.hardroot & "descriptors/pressrelease.xml")/> Yes - I addressed this in a later email yesterday - but (see below) this = won't even be necessary. Have the register() function read and parse the XML - less for the=20 developer to do. I'd probably go further and have a fixed=20 initialization file (XML) that the system finds 'automatically',=20 perhaps based on the location of Application.cfm, that lists all the=20 types that the system will use. Again, just syntactic sugar. I didn't want to mention it until I got something working (so as not to = add to the confusion), but I do think there should be a single = application settings file: modus.xml. It basically provides the mappings = to the descriptors and is also a great place for global defaults like = persistence type.and db source name (if needed)... The only thing a = contentObject developer will need to touch is the descriptor files. The = only thing a Modus user will need to touch is the modus.xml file to = register the contentObjects. So long as the include of initModus.cfm is = put into Application.cfm (a powerful new feature of coldfusion that I've = just invented by the way) the whole system initializes itself. Just a note - I've basically got the persistence layer running as a = service. The existing code base is proving quite simple to port. Thanks = for all of the hard work Nathan, I should be sharing something soon and = look forward to your feedback. -Jeremy |
From: Sean A C. <se...@co...> - 2002-11-08 17:50:22
|
On Thursday, Nov 7, 2002, at 14:22 US/Pacific, Jeremy Firsenbaum wrote: > The attached file starts with=A0an include of initModus.cfm. This file=20= > is responsible for setting the framework=A0up and so must be included = on=20 > every request. I would hope that most developers are=A0using=A0a=20 > methodology that=A0can accomodate global includes. It's simple with=20 > fusebox=A0- you just add=A0it to fbx_settings, but=A0a looser set up=20= > would=A0need to=A0do it some other way. What, like Application.cfm? :) > =A0<!--- Include and parse contentObject descriptors ---> > =A0<cffile action=3D"READ"=20 > file=3D"#application.hardroot#\descriptors\pressrelease.xml"=20 > variable=3D"pressrelease"> > =A0<cfset pressreleasexml =3D xmlParse(pressrelease)> > =A0 > =A0<!--- Register contentObjects ---> > =A0<cfset server.modus.registry.register(pressreleasexml)> Why not just: <cfset server.modus.registry.register(application.hardroot & "descriptors/pressrelease.xml")/> Have the register() function read and parse the XML - less for the=20 developer to do. I'd probably go further and have a fixed=20 initialization file (XML) that the system finds 'automatically',=20 perhaps based on the location of Application.cfm, that lists all the=20 types that the system will use. Again, just syntactic sugar. > That should be enough to get things rolling. The registry instantiates=20= > the appropriate facade as defined in the descriptor and passes it the=20= > xml. The facade then instantiates the appropriate modules:=20 > persistence, validation, renderer... and the developer need=20 > only=A0concern themselves with calling the UDF functions.=A0Almost = magical=20 > if you ask me. Yup. > If any of that made sense, then we're getting somewhere. It's becoming=20= > clearer in my own mind=A0as we hash this out - Sean continues to steer=20= > things in a solid direction. I should be able to get a simple=20 > proof-of-concept=A0up and running over the weekend. Let me know what = you=20 > think. Thanx for working on this Jeremy! Sean A Corfield -- http://www.corfield.org/blog/ "If you're not annoying somebody, you're not really alive." -- Margaret Atwood |
From: Sean A C. <se...@co...> - 2002-11-08 17:50:14
|
On Thursday, Nov 7, 2002, at 10:42 US/Pacific, Nathan Dintenfass wrote: > It seems we are perhaps heading down a road that is lowering the > value-add > of Modus. Perhaps I'm not getting it, though ;) I thought we were adding value! :) > If an object instance is basically just a struct that is created based > on > XML descriptor which does nothing more than define data types for > "fields", > and I then need to create UDF libraries to accomplish basic tasks, I > am not > sure we're getting much that can't be done by just having database > tables in > the first place. No, Modus would contain a UDF library that does most of the work. You would be able to extend base classes and then specify your extended classes in the XML and Modus would magically use them. Modus would do the basic stuff automatically for you tho'... > Here's my real concern: I haven't figured out how to have something > like a > "webImage" field in a "dumb" field set up. "webImage" would be a valid Modus field type - just as it is now - and the default persistence would treat it as a string, the default validator would probably do nothing (maybe check it was a valid path / filename?), the default renderer would generate: <img src="..."> The *field* is essentially dumb but the renderer knows it is an image. > That is, right now in the > modusTest application I can have an image and it takes no more work > than > having a piece of text -- that is powerful from a development > standpoint. > What would that look like in the set up you are suggesting? toHTML( myObj, "nameOfImageField" ); which in turn calls: myObj._modus.getField( myObj, "nameOfImageField" ).toHTML(); or something like that (I haven't quite figured the best way to bind persister, validator, renderer together in the facade... maybe the UDFs know and it looks like this instead: myObj._modus.renderer.toHTML( myObj, "nameOfImageField" ); which in turn calls: myObj._modus.validator.getField( myObj, "nameOfImageField" ); which in turn calls: myObj._modus.persister.getField( myObj, "nameOfImageField" ); it all depends how 'lazy' the persister and validator are). > I'm also a little concerned about the complexity with having the end > developer needing to pass around the XML descriptors to base > components. Nope, no complexity. The developer specifies the object in XML, indicating type, persistence (optional), rendering (optional). The application arranges to include a Modus initialization file - as Jeremy showed - which registers the XML descriptors (just once) and that's it, you're off to the races! > basic Modus API (ie: pressRelease.getField("title").toHTML()) to make pressRelease = get(prid); toHTML( pressRelease, "title" ); Sean A Corfield -- http://www.corfield.org/blog/ "If you're not annoying somebody, you're not really alive." -- Margaret Atwood |
From: Jeremy F. <jfi...@ma...> - 2002-11-07 22:30:19
|
honda is an object instance created by Modus - a struct. I'm = suggesting that when Modus creates an object instance, it stores a = reference to the facade that manages the instances inside the created = struct. This allows us - for an arbitrary Modus-managed object - to = perform any operations on the object simply by retrieving the facade = reference from inside it: function put(object) { object._modus.put(object); } I gotcha - one more level of abstraction. Rather than calling a separate = facade, let the udf figure out which facade to call. I was thinking: = honda.put() and vw.put(), while you're suggesting: put(honda), put(vw).=20 <cfif NOT isDefined('server.modus.facade')> <!--- Define and retrieve an xml descriptor- --> <cffile action=3D"READ" = file=3D"modustest\descriptors\pressrealease.xml" variable=3D"xml"> <cfset pressreleasexml =3D xmlParse(xml)> Well, I'd have this done through methods that register the type and do = it explicitly at startup: = server.modus.facade.register("modustest/descriptors/pressrelease.xml"); I think I see it now - check my "dumb vs. smart fields" reply for a = possible implementation. I had the xml parsing being done in a initModus = file, but that could all be handled internally, as your example shows, = by passing in the path. So: <!--- Include and parse contentObject descriptors ---> <cffile action=3D"READ" = file=3D"#application.hardroot#\descriptors\pressrelease.xml" = variable=3D"pressrelease"> <cfset pressreleasexml =3D xmlParse(pressrelease)> =20 <!--- Register contentObjects ---> <cfset server.modus.registry.register(pressreleasexml)> This becomes: <cfset = server.modus.registry.register("modustest\descriptors\pressrealease.xml")= > One difference here is that I have a separate registry cfc which = instantiates a facade for each contentObject, but as I said, let's wait = till the core is working before worrying about such things. -Jeremy |
From: Nathan D. <na...@ch...> - 2002-11-07 18:40:35
|
It seems we are perhaps heading down a road that is lowering the value-add of Modus. Perhaps I'm not getting it, though ;) If an object instance is basically just a struct that is created based on XML descriptor which does nothing more than define data types for "fields", and I then need to create UDF libraries to accomplish basic tasks, I am not sure we're getting much that can't be done by just having database tables in the first place. Here's my real concern: I haven't figured out how to have something like a "webImage" field in a "dumb" field set up. That is, right now in the modusTest application I can have an image and it takes no more work than having a piece of text -- that is powerful from a development standpoint. What would that look like in the set up you are suggesting? I'm also a little concerned about the complexity with having the end developer needing to pass around the XML descriptors to base components. I rather like the notion that someone can define a press release, and the person who is going to use the press release needs to know only the most basic Modus API (ie: pressRelease.getField("title").toHTML()) to make functional pages. Though, y'all clearly are more experienced in the OO design patterns than I am, I just want to make sure a developer doesn't need to know much about that to be productive in Modus. But, I'm a worrier ;) - n |
From: Sean A C. <se...@co...> - 2002-11-07 16:15:47
|
On Thursday, Nov 7, 2002, at 06:23 US/Pacific, Jeremy Firsenbaum wrote: > It will probably be easier to address this once we have a core to put=20= > a facade on. Agreed. > Haven't quite grokked this suggestion. How would honda._modus be used? honda is an object instance created by Modus - a struct. I'm suggesting=20= that when Modus creates an object instance, it stores a reference to=20 the facade that manages the instances inside the created struct. This=20 allows us - for an arbitrary Modus-managed object - to perform any=20 operations on the object simply by retrieving the facade reference from=20= inside it: function put(object) { object._modus.put(object); } > <cfif NOT isDefined('server.modus.facade')> > <!--- Define and retrieve an xml descriptor- --> > <cffile action=3D"READ" file=3D"modustest\descriptors\pressrealease.xml"= =20 > variable=3D"xml"> > <cfset pressreleasexml =3D xmlParse(xml)> Well, I'd have this done through methods that register the type and do=20= it explicitly at startup: = server.modus.facade.register("modustest/descriptors/pressrelease.xml"); > Internally, the facade parses the xml and instantiates the appropriate=20= > modules. That means that the descriptor is really driving the whole=20 > thing. Yes. > Would the=A0honda._modus idea fit into this picture? See above - it's for *instances* only. "SOAP is not so much a means of transmitting data but a mechanism for calling COM objects over the Web." -- not Microsoft (surprisingly!) |
From: Jeremy F. <jfi...@ma...> - 2002-11-07 14:24:17
|
Yes, a static CFC is really just a wrapper for the UDFs I was = considering anyway - but I was trying to avoid the = server.staticInstance.methodCall(object) syntax and reduce it to = methodCall(object) - it's just a matter of degree. It will probably be easier to address this once we have a core to put a = facade on. It might turn out that this would be application specific so = that you could have a facade in server scope with udf calls as a mask, = or the facade itself might store some instance data so that you would = store it in session scope. The advantage here would be the ability to = plug in a security module that has access to user permissions and the = like. What's more the facade could even be instantiated per request if = needed. I think the point is to build the core modules and see where = that leaves us. I imagine a single attribute in each 'object' that is a reference to = the Modus entity through which the Modus methods interact. Given the = three services and the facade mentioned above, that attribute would = either be a reference to the facade instance or a struct containing = references to all of the above. The reason that might be important is to = allow non-persistent objects, non-valdated objects and non-rendering = objects. Of course, if we have 'null' versions of those and we construct = the facade instance from the three service objects, then we could fall = back to just a references to the facade instance. In other words, you're talking about honda.fields.x and I'm = suggesting adding honda._modus to refer to the single facade instance. = It would be added automatically by Modus object creation / retrieval = methods and used by store / update / etc methods. Haven't quite grokked this suggestion. How would honda._modus be used? = Here's sort of how I'm thinking Modus would be used: In a global include: <cfif NOT isDefined('server.modus.facade')> <!--- Define and retrieve an xml descriptor- --> <cffile action=3D"READ" file=3D"modustest\descriptors\pressrealease.xml" = variable=3D"xml"> <cfset pressreleasexml =3D xmlParse(xml)> <!--- Instantiate the facade - we're putting this into the server scope, = but it doesn't have to be ---> <cfset server.modus.facade.pressrelease=3D = createObject("component","org.bacfug.modus.facade.basefacade").init(press= releasexml)> <!--- Continue the same process as above for all content objects ---> </cfif> Internally, the facade parses the xml and instantiates the appropriate = modules. That means that the descriptor is really driving the whole = thing. Would the honda._modus idea fit into this picture? -Jeremy |
From: Sean A C. <se...@co...> - 2002-11-07 03:24:18
|
On Tuesday, Nov 5, 2002, at 17:00 US/Pacific, Jeremy Firsenbaum wrote: > Yes, yes. That is kind of what Sean was getting at when he mentioned=20= > syntactic sugar. You can have a wrapper or facade component that=20 > handles all of the interaction with the=A0"dumb" layers of the system.=20= > Sean had actually mentioned a few=A0UDFs, but I think another static = CFC=20 > would be the Yes, a static CFC is really just a wrapper for the UDFs I was=20 considering anyway - but I was trying to avoid the=20 server.staticInstance.methodCall(object) syntax and reduce it to=20 methodCall(object) - it's just a matter of degree. > So a service-based Modus might have the following components: > =A0 > Persister - this is responsible for moving data on and off disk. It=20 > should maintain=A0the memory-based cache as well. > =A0 > ContentObject - this essentially provides data validation services.=20 > Anything else? > =A0 > Renderer - suited primarily to HTML for now. At the least this=A0takes=20= > over for renderBasicForm(). > =A0 > Facade - the sole instance that is created externally. It=A0finds or=20= > instantiates the appropriate components as defined in the descriptor.=20= > Provides coarser-grained access to the dirty work of retrieving,=20 > rendering, validating and storing a contentObject. This is where the=20= > "substantially less coding" requirement is fulfilled. Yes, this fits well with my proto-thoughts on a service-based=20 architecture. Thanx Jeremy. > That might be tricky to provide method-based access since the=20 > persister would probably work best if it returned a struct. For=20 > example: honda.fields.color =3D "blue". In fact, the EJB example that = I=20 > mentioned does just this.=A0They use a=A0value object java bean to = return=20 > a methodless instance of the EJB and coldfusion treats it=A0just = like=A0a=20 > struct. I hate to see the methods go too, making the system feel less=20= > object-like, but it seems to be the best solution for getting data in=20= > and out of static components. Bear in mind that CFMX already turns honda.fields.color into a series=20 of method calls so adding getField() and setValue() methods really only=20= adds overhead. We need to remember that CFMX is not Java :) I imagine a single attribute in each 'object' that is a reference to=20 the Modus entity through which the Modus methods interact. Given the=20 three services and the facade mentioned above, that attribute would=20 either be a reference to the facade instance or a struct containing=20 references to all of the above. The reason that might be important is=20 to allow non-persistent objects, non-valdated objects and non-rendering=20= objects. Of course, if we have 'null' versions of those and we=20 construct the facade instance from the three service objects, then we=20 could fall back to just a references to the facade instance. In other words, you're talking about honda.fields.x and I'm suggesting=20= adding honda._modus to refer to the single facade instance. It would be=20= added automatically by Modus object creation / retrieval methods and=20 used by store / update / etc methods. Am I making sense? "I can smell your brains!" -- Mittens the Kitten : http://www.matazone.co.uk/theotherside.html |
From: Jeremy F. <jfi...@ma...> - 2002-11-06 01:00:46
|
Perhaps we can have it both ways -- build a "dumb" contentObject infrastructure that is used in various services, then create some = wrapper components that perform like "smart" components by encapsulating = common tasks one does with the dump contentObjects and the services. Hmm, = that might actually be quite nice and provide a nice gradual learning curve = for a developer (starting with the "smart" layer and then being able to = branch out into their own customized use of the "dumb" contentObjects with = services). It would also, I can see, make it easier to extend Modus by layering = on services instead of having to change baseContentObject. I guess I'm = sold on the general concept, though I want to make sure that building a simple = Modus app requires substantially less coding then building a "regular" CF = app (which is where this whole thing started). Yes, yes. That is kind of what Sean was getting at when he mentioned = syntactic sugar. You can have a wrapper or facade component that handles = all of the interaction with the "dumb" layers of the system. Sean had = actually mentioned a few UDFs, but I think another static CFC would be = the The persistence layer can be entirely separate from the = contentObject layer as well as a display layer because the glue that = ties the whole system together is the xml descriptor. That's really = where the "smartness" lies. All components have to be able to handle = this in a standard way since it is the object definition. So a service-based Modus might have the following components: Persister - this is responsible for moving data on and off disk. It = should maintain the memory-based cache as well. ContentObject - this essentially provides data validation services. = Anything else? Renderer - suited primarily to HTML for now. At the least this takes = over for renderBasicForm(). Facade - the sole instance that is created externally. It finds or = instantiates the appropriate components as defined in the descriptor. = Provides coarser-grained access to the dirty work of retrieving, = rendering, validating and storing a contentObject. This is where the = "substantially less coding" requirement is fulfilled. As you said Nathan, this leaves open lots of room to plug in more = services, such as security, locking for data integrity and whatever = else. And if done well, the only code that would need to change would be = the facade. As I've been working on the collections idea we hashed out last week it = seems that it would be more efficient for each object to provide its own = extension to the persister. An approach similar to this is shown in the = 4th chapter of Ben Forta's new J2EE book. They have EJBs for simple data = access/mutation, but use SQL wrapped in CFCs for complex queries. With = Modus we could put the complex queries in the contentObject's own = persister. For example, pressrealease_dao extends dbpersister with a = "getAllRelated()" method. This would provide a significant performance = boost for searches and sorts, particularly for the table-based = dbpersister I've been working on. But, it would also work for the = wddx-based persisters, maybe even using Xpath searches on the wddx = itself since CFMX supports that now. Much of this could probably even be = defined in the descriptor so that developers wouldn't need to worry = about the code for simple joins. Starting to sound like container = managed persistence, huh? In any case, I've got something like this = working in the forums app I started called getQueryByCategory, so it's = not too far fetched. I'll have to noodle on Jeremy's proposed API (and yes, I realize it = was meant as a proof of concept, not a finished product). =20 Yes, I haven't actually implemented anything, although I don't think it = would take much to make this work from the existing code base. The first = and most important step is going to be the xml descriptor. I still think we should maintain a development style that uses = methods, ie: honda.getField("color").setValue("blue") rather than just honda.color = =3D "blue" -- mostly to keep things consistent and because it just feels = tighter to me for some reason. Though, perhaps it's overly verbose. The last = big project I managed we used Turbine (from Apache) and it allowed you to = do honda.color, but under the sheets it turned that into honda.getColor() = -- that is, it was a short-hand way to access the method rather than = exposed data members. That might be tricky to provide method-based access since the persister = would probably work best if it returned a struct. For example: = honda.fields.color =3D "blue". In fact, the EJB example that I mentioned = does just this. They use a value object java bean to return a methodless = instance of the EJB and coldfusion treats it just like a struct. I hate = to see the methods go too, making the system feel less object-like, but = it seems to be the best solution for getting data in and out of static = components. -Jeremy |
From: Nathan D. <na...@ch...> - 2002-11-05 23:51:34
|
Hmm. Well, I'll have to mentally chew on this a bit. I can see the benefit of having persistence not embedded in the contentObject, but given that I can still store my persister as a "static" component in memory and then just have each contentObject instance refer to it, it seems that performance at that level should not be too big an issue. Then we have the issue of what is a contentObject -- is it basically just a data descriptor which is then passed to a variety of services, or does it have a lot of functionality built in. I'll construct this discussion as "dumb" contentObjects vs. "smart" contentObjects. Perhaps we can have it both ways -- build a "dumb" contentObject infrastructure that is used in various services, then create some wrapper components that perform like "smart" components by encapsulating common tasks one does with the dump contentObjects and the services. Hmm, that might actually be quite nice and provide a nice gradual learning curve for a developer (starting with the "smart" layer and then being able to branch out into their own customized use of the "dumb" contentObjects with services). It would also, I can see, make it easier to extend Modus by layering on services instead of having to change baseContentObject. I guess I'm sold on the general concept, though I want to make sure that building a simple Modus app requires substantially less coding then building a "regular" CF app (which is where this whole thing started). I'll have to noodle on Jeremy's proposed API (and yes, I realize it was meant as a proof of concept, not a finished product). I still think we should maintain a development style that uses methods, ie: honda.getField("color").setValue("blue") rather than just honda.color = "blue" -- mostly to keep things consistent and because it just feels tighter to me for some reason. Though, perhaps it's overly verbose. The last big project I managed we used Turbine (from Apache) and it allowed you to do honda.color, but under the sheets it turned that into honda.getColor() -- that is, it was a short-hand way to access the method rather than exposed data members. You know, in some ways a "dumb" contentObject may be little more than its descriptor (and perhaps nothing more than its descriptor). Oh, and for performance I was talking about 500ms per PAGE, not per instance, so I think we're on the same page after all. The modusTest app with the current build gets close to this, even on my not-so-great workstation with lots of other stuff running. And, most of the processing time is in the getAllSorted(), which is atrocious (other suggestions on how to accomplish sorting are welcomed!). - Nathan > -----Original Message----- > From: mod...@li... > [mailto:mod...@li...]On Behalf Of Sean A > Corfield > Sent: Tuesday, November 05, 2002 9:31 AM > To: mod...@li... > Subject: Re: [Modus-devs] Some general Modus comments to start with > > > On Tuesday, Nov 5, 2002, at 08:05 US/Pacific, Nathan Dintenfass wrote: > > I've gotta run out, but just a quick note . . . > > I'm on BART, but just a quick note . . . :) > > > Yes, agreed. The notion of the "persister" in Modus is a move towards > > abstracting the persistence layer away from the contentObject API > > itself > > (though, the baseContentObject has some convenience methods that pass > > through the persister). > > Excellent! I wasn't clear from our earlier conversations whether that > was indeed a guiding principle for you or not. > > > Right now, each instance of the baseContentObject > > has its own reference to a persister (which in the current "build" > > literally > > creates a new instance of a persister!!), and each contentObjectType > > will > > have will have the ability to say which persister it wants to use (any > > persister must extend and "implement" the basePersister). > > Yes, that makes sense. > > > I do think that > > before 1.0 we need to move away from having a separate instance of a > > persister in each contentObject instance, but I am not sure if the > > developer > > should need to worry about the persister -- that is, it seems very user > > friendly to be able to just say pressRelease.save() and have that deal > > internally with passing this to the persister.store(). Would you > > disagree? > > Well, the problem with that is that it means each content object > instance must inherit from a class that knows how to save() and load() > and so on. It's precisely this overhead that I'm suggesting we try to > avoid. As Jeremy has discovered, object instantiation times are > affected dramatically by inheritance and the # of methods. > > Furthermore, there's actually a problem with inheriting from a class > that knows about persistence - in fact there are two main (design) > problems: > 1. it forces all your content objects to be persistable (or at least > know about the persistence machinery) > 2. it precludes making a content object from something that inherits > from some other base type > > Let me explain those: > 1. all content objects have save() and load() methods (because their > base class has them) but you may want transient content objects - so it > raises the question of what the default implementation for those > methods is (as you say, you can have a range of persisters). > 2. is the bigger issue. Suppose I have a vehicle component and I > derived car and train from that. I can't easily make a persistent car > if I need to inherit from some content object base class. This is why > C++ has mixins and why Java has interfaces. You need a way to blend the > implementation of one entity (car in this case) with the *interface* of > another (content object in this case). > > My suggested approach - making persistence a *service* - allows you to > side-step this. I can easily make my car object persistable by creating > an XML descriptor for it (externally) and then binding it into the > persistence system dynamically. Sure, it means you can't save > honda.save() and instead you need to create a carPersister (binding in > the car XML descriptor) and then say carPersister.save(honda) but that > isn't really a big hardship - yet it buys a lot of flexibility AND it > removes the per-instance overhead of the persistence mechanism > (methods, metadata, inheritance). > > If CF had real interfaces, I wouldn't be as worried about this from a > design point of view. If CF was higher-performance in its OO support, I > might also concede this point on the grounds of simplicity. But neither > of those are true so I'm going to stick to the idea of > persistence-as-service (and would push for presentation-as-service too). > > Besides, a plugin-based architecture like that is very flexible and is > well-enough documented in the literature that developers shouldn't find > it too alien (note that Fusebox MX uses a plugin architecture, much to > my surprise - and delight!). > > > Well, they may load faster on the server, but then the Flash movie > > has to "load" -- the perceived time on MANY pages (including the home > > page) > > at macromedia.com is well over 1 second, no?? > > Yes, in fact our target for load time is well over a second - for a > fully-loaded, interactive page (I don't have the thresholds on hand). > However, what we are talking about with Modus is the time it takes to > load individual objects. A very common scenario on a website is a > summary page that displays, say, twenty items for the user to scroll > through. If it takes Modus 500ms to load an object and render two or > three fields (title, date, author for example), then that page will > take well over TEN SECONDS to load in total. I would say that we should > be aiming for a system that can load and render a 50 item summary table > in around 5 seconds. That's a combined load and render time of just > 100ms per item. > > "I can smell your brains!" > -- Mittens the Kitten : http://www.matazone.co.uk/theotherside.html > > > > ------------------------------------------------------- > This sf.net email is sponsored by: See the NEW Palm > Tungsten T handheld. Power & Color in a compact size! > http://ads.sourceforge.net/cgi-bin/redirect.pl?palm0001en > _______________________________________________ > Modus-devs mailing list > Mod...@li... > https://lists.sourceforge.net/lists/listinfo/modus-devs > |
From: Sean A C. <se...@co...> - 2002-11-05 21:29:25
|
You are spot on! Yes! Of course, it needs a little syntactic sugar to=20 tidy up the initialization... On Tuesday, Nov 5, 2002, at 12:29 US/Pacific, Jeremy Firsenbaum wrote: > A few thoughts that might add to the discussion as I try to make sense=20= > of Sean's proposal in light of Modus' current architecture: > > > My suggested approach - making persistence a *service* - allows you to > side-step this. I can easily make my car object persistable by = creating > an XML descriptor for it (externally) and then binding it into the > persistence system dynamically. Sure, it means you can't save > honda.save() and instead you need to create a carPersister (binding in > the car XML descriptor) and then say carPersister.save(honda) but that > isn't really a big hardship - yet it buys a lot of flexibility AND it > removes the per-instance overhead of the persistence mechanism > (methods, metadata, inheritance). > > So if I'm reading this correctly, you would do a one time call like: > =A0 > <cfif NOT isDefined('server.carDescriptor')> > <cffile action=3D"READ" file=3D"car.xml" variable=3D"carxml"> > <cfscript> > =A0=A0=A0 carDescriptor =3D xmlParse(carxml); > =A0=A0=A0=A0server.carPersister =3D=20 > createObject("component","modus.simpleobjectinstance"); > =A0=A0=A0 server.carPersister.init(carDescriptor); > </cfscript> > </cfif> > =A0 > carPersister would return=A0a structure of data, not an object = instance.=20 > All of the work that contentObject had done to instantiate=A0an=20 > object=A0would be taken over by=A0the persister. It would simply = populate=20 > a structure according to the xml descriptor, rather than=A0inheriting=20= > from=A0basecontentobject, working through the metadata and = instantiating=20 > individual fields to hold data.=A0The persister=A0might be used=A0like = so: > =A0 > myCar =3D server.carPersister.get(carID); > myCar.tires =3D 4; > myCar.color =3D "blue"; > server.carPersister.save(myCar); > =A0 > > If CF had real interfaces, I wouldn't be as worried about this from a > design point of view. If CF was higher-performance in its OO support, = I > might also concede this point on the grounds of simplicity. But = neither > of those are true so I'm going to stick to the idea of > persistence-as-service (and would push for presentation-as-service=20 > too). > > and I think Sean is even suggesting that the=A0contentObject be made a=20= > static or service-oriented=A0component as well, doing such things as=20= > data validation.=A0For example: > =A0 > <cfif NOT isDefined('server.car')> > <cffile action=3D"READ" file=3D"car.xml" variable=3D"carxml"> > <cfscript> > =A0=A0=A0 car =3D xmlParse(carxml); > =A0=A0=A0=A0server.car =3D=20 > createObject("component","modustest.contentobjects.car"); > =A0=A0=A0 server.car.init(carDescriptor); > </cfscript> > </cfif> > =A0 > and then car and carPersister could be used together like: > =A0 > myCar =3D server.carPersister.get(carID); > myCar.tires =3D 4; > myCar.color =3D "blue"; > myCar =3D server.car.validate(myCar); > if (NOT myCar.hasErrors){ > =A0=A0=A0 server.carPersister.save(myCar); > } > > Besides, a plugin-based architecture like that is very flexible and is > well-enough documented in the literature that developers shouldn't = find > it too alien (note that Fusebox MX uses a plugin architecture, much to > my surprise - and delight!). > > The form generator could be just another plug-in that reads the xml,=20= > receives an object-as-struct from the data store and returns the html.=20= > Incidentally, I worked on a form generator cfc this summer that does=20= > just this: accepts an xml object, constructs the html (with stylesheet=20= > support) and return the form as a string. Even for complicated forms=20= > with multiple select lists and such it never took more the 40ms to do=20= > its work. > =A0 > As Sean said, we'd be=A0losing the content object 'as object' in favor=20= > of more flexibility and greater performance. Sure the data is all=20 > exposed as a structure, rather than kept nice and tidy behind=20 > accessor/mutator methods, but CF doesn't seem to be ready to handle=20 > the full OO shebang. > =A0 > Just thinking out loud here. What do you think? > =A0 > -Jeremy > "If you're not annoying somebody, you're not really alive." -- Margaret Atwood |
From: Jeremy F. <jfi...@ma...> - 2002-11-05 20:30:31
|
A few thoughts that might add to the discussion as I try to make sense = of Sean's proposal in light of Modus' current architecture: My suggested approach - making persistence a *service* - allows you to = side-step this. I can easily make my car object persistable by = creating=20 an XML descriptor for it (externally) and then binding it into the=20 persistence system dynamically. Sure, it means you can't save=20 honda.save() and instead you need to create a carPersister (binding in = the car XML descriptor) and then say carPersister.save(honda) but that = isn't really a big hardship - yet it buys a lot of flexibility AND it=20 removes the per-instance overhead of the persistence mechanism=20 (methods, metadata, inheritance). So if I'm reading this correctly, you would do a one time call like: <cfif NOT isDefined('server.carDescriptor')> <cffile action=3D"READ" file=3D"car.xml" variable=3D"carxml"> <cfscript> carDescriptor =3D xmlParse(carxml); server.carPersister =3D = createObject("component","modus.simpleobjectinstance"); server.carPersister.init(carDescriptor); </cfscript> </cfif> carPersister would return a structure of data, not an object instance. = All of the work that contentObject had done to instantiate an object = would be taken over by the persister. It would simply populate a = structure according to the xml descriptor, rather than inheriting from = basecontentobject, working through the metadata and instantiating = individual fields to hold data. The persister might be used like so: myCar =3D server.carPersister.get(carID); myCar.tires =3D 4; myCar.color =3D "blue"; server.carPersister.save(myCar); If CF had real interfaces, I wouldn't be as worried about this from a=20 design point of view. If CF was higher-performance in its OO support, = I=20 might also concede this point on the grounds of simplicity. But = neither=20 of those are true so I'm going to stick to the idea of=20 persistence-as-service (and would push for presentation-as-service = too). and I think Sean is even suggesting that the contentObject be made a = static or service-oriented component as well, doing such things as data = validation. For example: <cfif NOT isDefined('server.car')> <cffile action=3D"READ" file=3D"car.xml" variable=3D"carxml"> <cfscript> car =3D xmlParse(carxml); server.car =3D = createObject("component","modustest.contentobjects.car"); server.car.init(carDescriptor); </cfscript> </cfif> and then car and carPersister could be used together like: myCar =3D server.carPersister.get(carID); myCar.tires =3D 4; myCar.color =3D "blue"; myCar =3D server.car.validate(myCar); if (NOT myCar.hasErrors){ server.carPersister.save(myCar); } Besides, a plugin-based architecture like that is very flexible and is = well-enough documented in the literature that developers shouldn't = find=20 it too alien (note that Fusebox MX uses a plugin architecture, much to = my surprise - and delight!). The form generator could be just another plug-in that reads the xml, = receives an object-as-struct from the data store and returns the html. = Incidentally, I worked on a form generator cfc this summer that does = just this: accepts an xml object, constructs the html (with stylesheet = support) and return the form as a string. Even for complicated forms = with multiple select lists and such it never took more the 40ms to do = its work. As Sean said, we'd be losing the content object 'as object' in favor of = more flexibility and greater performance. Sure the data is all exposed = as a structure, rather than kept nice and tidy behind accessor/mutator = methods, but CF doesn't seem to be ready to handle the full OO shebang.=20 Just thinking out loud here. What do you think? -Jeremy |
From: Sean A C. <se...@co...> - 2002-11-05 17:30:45
|
On Tuesday, Nov 5, 2002, at 08:05 US/Pacific, Nathan Dintenfass wrote: > I've gotta run out, but just a quick note . . . I'm on BART, but just a quick note . . . :) > Yes, agreed. The notion of the "persister" in Modus is a move towards > abstracting the persistence layer away from the contentObject API > itself > (though, the baseContentObject has some convenience methods that pass > through the persister). Excellent! I wasn't clear from our earlier conversations whether that was indeed a guiding principle for you or not. > Right now, each instance of the baseContentObject > has its own reference to a persister (which in the current "build" > literally > creates a new instance of a persister!!), and each contentObjectType > will > have will have the ability to say which persister it wants to use (any > persister must extend and "implement" the basePersister). Yes, that makes sense. > I do think that > before 1.0 we need to move away from having a separate instance of a > persister in each contentObject instance, but I am not sure if the > developer > should need to worry about the persister -- that is, it seems very user > friendly to be able to just say pressRelease.save() and have that deal > internally with passing this to the persister.store(). Would you > disagree? Well, the problem with that is that it means each content object instance must inherit from a class that knows how to save() and load() and so on. It's precisely this overhead that I'm suggesting we try to avoid. As Jeremy has discovered, object instantiation times are affected dramatically by inheritance and the # of methods. Furthermore, there's actually a problem with inheriting from a class that knows about persistence - in fact there are two main (design) problems: 1. it forces all your content objects to be persistable (or at least know about the persistence machinery) 2. it precludes making a content object from something that inherits from some other base type Let me explain those: 1. all content objects have save() and load() methods (because their base class has them) but you may want transient content objects - so it raises the question of what the default implementation for those methods is (as you say, you can have a range of persisters). 2. is the bigger issue. Suppose I have a vehicle component and I derived car and train from that. I can't easily make a persistent car if I need to inherit from some content object base class. This is why C++ has mixins and why Java has interfaces. You need a way to blend the implementation of one entity (car in this case) with the *interface* of another (content object in this case). My suggested approach - making persistence a *service* - allows you to side-step this. I can easily make my car object persistable by creating an XML descriptor for it (externally) and then binding it into the persistence system dynamically. Sure, it means you can't save honda.save() and instead you need to create a carPersister (binding in the car XML descriptor) and then say carPersister.save(honda) but that isn't really a big hardship - yet it buys a lot of flexibility AND it removes the per-instance overhead of the persistence mechanism (methods, metadata, inheritance). If CF had real interfaces, I wouldn't be as worried about this from a design point of view. If CF was higher-performance in its OO support, I might also concede this point on the grounds of simplicity. But neither of those are true so I'm going to stick to the idea of persistence-as-service (and would push for presentation-as-service too). Besides, a plugin-based architecture like that is very flexible and is well-enough documented in the literature that developers shouldn't find it too alien (note that Fusebox MX uses a plugin architecture, much to my surprise - and delight!). > Well, they may load faster on the server, but then the Flash movie > has to "load" -- the perceived time on MANY pages (including the home > page) > at macromedia.com is well over 1 second, no?? Yes, in fact our target for load time is well over a second - for a fully-loaded, interactive page (I don't have the thresholds on hand). However, what we are talking about with Modus is the time it takes to load individual objects. A very common scenario on a website is a summary page that displays, say, twenty items for the user to scroll through. If it takes Modus 500ms to load an object and render two or three fields (title, date, author for example), then that page will take well over TEN SECONDS to load in total. I would say that we should be aiming for a system that can load and render a 50 item summary table in around 5 seconds. That's a combined load and render time of just 100ms per item. "I can smell your brains!" -- Mittens the Kitten : http://www.matazone.co.uk/theotherside.html |
From: Nathan D. <na...@ch...> - 2002-11-05 16:03:38
|
I've gotta run out, but just a quick note . . . > > Yes, definitely not just persistence. It's about doing away with a > > lot of > > mundane, repetitive tasks while offering a tight metaphor for coding. > > I guess my concern is that I believe we need a solid persistence layer > first, on which to build an application framework. I'm worried that by > trying to create a single all-purpose layer, it won't do either very > well. Yes, agreed. The notion of the "persister" in Modus is a move towards abstracting the persistence layer away from the contentObject API itself (though, the baseContentObject has some convenience methods that pass through the persister). Right now, each instance of the baseContentObject has its own reference to a persister (which in the current "build" literally creates a new instance of a persister!!), and each contentObjectType will have will have the ability to say which persister it wants to use (any persister must extend and "implement" the basePersister). I do think that before 1.0 we need to move away from having a separate instance of a persister in each contentObject instance, but I am not sure if the developer should need to worry about the persister -- that is, it seems very user friendly to be able to just say pressRelease.save() and have that deal internally with passing this to the persister.store(). Would you disagree? > > True, true. Though, personally performance tends to be a lower > > priority for > > me because I rarely work on sites that have huge volume. > > I think performance is important enough in real life for enough CFers > that we do need to consider it. Yes, but not prioritize it. I just think there are more important concerns for Modus given the audience. Thus, performance must be acceptable, not optimal. > > > wouldn't be a big deal in my mind if Modus 1.0 was not an "Enterprise > > Class" > > system if it is useful to a large swath of CF folks. > > It would be nice if Modus 2.0 was not radically different to Modus 1.0 > tho' so I think we need to get enough confidence in the APIs and > architecture of Modus 1.0 in terms of basic performance - or the > ability to improve performance without changing the API / architecture. Oh, absolutely. I think the API should be fairly stable before it's called 1.0 -- I am talking about making extensions to it in 2.0 and/or putting more energy into the underlying machinery for 2.0. > > > Well, depends on what "fast" means. Is less than 500 ms for a page > > that > > both displays all the press releases and has everything necessary to > > edit > > one (including having retrieved one from persistence to get it ready to > > edit)? For most applications that is acceptable performance. Is it > > great? > > I don't believe it's acceptable. Hmm, we'll have to agree to disagree. The vast majority of ColdFusion sites never deal with many simultaneous requests. I think 500ms should be a ceiling, but it is within a range for a "heavy" page that is not out of bounds, IMO. What would an acceptable ceiling be for you? I'm actually a little surprised given how many pages on macromedia.com don't possibly load faster. Well, they may load faster on the server, but then the Flash movie has to "load" -- the perceived time on MANY pages (including the home page) at macromedia.com is well over 1 second, no?? |
From: Sean A C. <se...@co...> - 2002-11-05 04:44:25
|
On Friday, Nov 1, 2002, at 16:19 US/Pacific, Nathan Dintenfass wrote: > Well, I've managed to eat up sizable portions of my Friday talking > Modus. > Which is fun. :) > Yes, definitely not just persistence. It's about doing away with a > lot of > mundane, repetitive tasks while offering a tight metaphor for coding. I guess my concern is that I believe we need a solid persistence layer first, on which to build an application framework. I'm worried that by trying to create a single all-purpose layer, it won't do either very well. > Jeremy has demonstrated, that Modus 1.0 could be used in the > context of Fusebox -- though eventually Modus (or a related project) > may > grow to supersede much of what Fusebox is about. I think it will be interesting to see how "Fusebox MX" will be received... but Fusebox does not address persistence so I believe a focused persistence layer can coexist peacefully with Fusebox MX :) > True, true. Though, personally performance tends to be a lower > priority for > me because I rarely work on sites that have huge volume. I think performance is important enough in real life for enough CFers that we do need to consider it. > wouldn't be a big deal in my mind if Modus 1.0 was not an "Enterprise > Class" > system if it is useful to a large swath of CF folks. It would be nice if Modus 2.0 was not radically different to Modus 1.0 tho' so I think we need to get enough confidence in the APIs and architecture of Modus 1.0 in terms of basic performance - or the ability to improve performance without changing the API / architecture. > Well, depends on what "fast" means. Is less than 500 ms for a page > that > both displays all the press releases and has everything necessary to > edit > one (including having retrieved one from persistence to get it ready to > edit)? For most applications that is acceptable performance. Is it > great? I don't believe it's acceptable. > "Linked" components (the "foreign key" reference model) are the way to > go > for Modus. Agreed. > Oh, yes. I never intended for pressRelease.renderHTML(), only > pressRelease.getField("image").renderHTML() -- which just outputs: > > <img src="http://[serverPath]/imageName.gif"> OK. I'd still prefer separation of presentation from persistence of course :) > Yes, label is "friendly name" -- localization is a great issue. I > guess it > seems like someone who is building a multi-lingual site will need to > find an > alternative way if they want some generic form generation to happen (or > submit changes to Modus that allow it ;) As long as the Modus architecture doesn't *preclude* localization, I'll be reasonably satisfied... "I can smell your brains!" -- Mittens the Kitten : http://www.matazone.co.uk/theotherside.html |
From: Nathan D. <na...@ch...> - 2002-11-02 00:17:50
|
Well, I've managed to eat up sizable portions of my Friday talking Modus. Which is fun. My answers inline below . . . > > On Friday, Nov 1, 2002, at 08:46 US/Pacific, Nathan Dintenfass wrote: > > Let me say first that Modus is not intended to be a general application > > framework -- it is focused on building web-delivered applications > > written in > > CFML. Given the intended use of Modus, the "80% case" is the target > > for the > > code base (particularly for 1.0). > > OK, but it sounds like it's intended to be "more general" than 'just' a > persistence mechanism which is part of what I'm really trying to get a > handle on. Yes, definitely not just persistence. It's about doing away with a lot of mundane, repetitive tasks while offering a tight metaphor for coding. I think, as Jeremy has demonstrated, that Modus 1.0 could be used in the context of Fusebox -- though eventually Modus (or a related project) may grow to supersede much of what Fusebox is about. > > > I come from a viewpoint that speed of > > development for a CFML developer wanting to build web pages that > > deliver > > dynamic content is a key consideration that, in my mind, may trump > > certain > > design philosophies. > > Agreed. And performance is probably a higher goal than 'sweet design > under the hood'. Take Fusebox as an example. True, true. Though, personally performance tends to be a lower priority for me because I rarely work on sites that have huge volume. I think the target for Modus is more likely the "typical CF site" where you never have a user base in the millions (or even in the hundreds of thousands). That is, it wouldn't be a big deal in my mind if Modus 1.0 was not an "Enterprise Class" system if it is useful to a large swath of CF folks. > > For me, the > > modustest app in its current form is a living proof-of-concept that > > demonstrates how very very easy it is for someone to very rapidly > > create a > > very simple CMS. > > Agreed, but it's not very fast, I gather :) Well, depends on what "fast" means. Is less than 500 ms for a page that both displays all the press releases and has everything necessary to edit one (including having retrieved one from persistence to get it ready to edit)? For most applications that is acceptable performance. Is it great? No. Could it be improved. Probably. But, as long as a typical Modus page can stay in that range it's probably good enough (for 1.0 anyway). We can go back later when the developer API is well baked to optimize (or people can build different caching and/or persistence mechanisms to speed things up). What I'm saying is that for 1.0 I think the primary objective should be tight metaphor, rapid development and "acceptable" performance. > > > As we move towards linked contentObjects and other > > "advanced" features I don't want to lose such ease of use for the base > > case. > > Agreed. I'm actually trying to ensure that we don't try to build in > features that make Modus complicated to use or make it terribly slow to > run. I would avoid embedded components for those very reasons. Agreed. Embedded components are a no go for the foreseeable future. "Linked" components (the "foreign key" reference model) are the way to go for Modus. > > > A lot of the discussion in the last 24 hours has started to revolve > > around > > what a field is and what the descriptor should know. These are both > > good > > discussions to have, particularly as we prepare to rewrite the guts to > > use > > the XML descriptor. > > Agreed. Can I put in a little vote for making the presentation > specifications optional? And having the renderXxx() method(s) throw an > exception if an attempt is made to render an object for which no > specification is given... Yes, I think that's reasonable. > > > The renderSimpleForm() is just a convenience that I think will move > > out of > > the baseContentObject and into some kind of contentObjectUtility. > > I think a field can render itself but I'm not sold on the idea of a > whole object rendering itself as HTML... Oh, yes. I never intended for pressRelease.renderHTML(), only pressRelease.getField("image").renderHTML() -- which just outputs: <img src="http://[serverPath]/imageName.gif"> That is probably the most extreme example of a field knowing about HTML. I absolutely agree that a contentObject should not even try to render itself in its entirety. I could see building some kind of display handler mechanism where I might do pressRelease.renderDisplay("handerName"), but that's not a priority for me. The renderHTML() on most field types just outputs the raw value -- I just think from an interface standpoint it's cleaner to use toHTML() rather than getValue() -- allows for things like a field type that is a "webImage" (one of the built in field types in 0.2) or perhaps a "colorPicker" (which might use a SWF or some other "rich" client). renderSimpleForm() is a different animal -- I guess I see that as something used only for the most basic of basic objects or for prototyping. I would imagine that in a product app that renderSimpleForm() would rarely be used. But, it's convenient enough that I built it in (works fabulously for something super simple like the current modustest application). Understand that I build a lot of "little" sites that do some fairly basic CMS for small businesses, hobby sites, personal sites, etc. -- Modus was started more to help me slam those out than to build something like macromedia.com (though, it's nice to have that perspective on the team to keep me from making blunders and, frankly, for my own education about OO frameworks/methods/patterns). > > > I could be much more easily convinced to do away with "label" and > > renderSimpleForm() than I could to not have fields know how to create > > the > > proper HTML form widget for themselves. But, it sure is handy to have > > that > > label ;) > > I think 'friendly name' is a good concept but it doesn't lend itself to > localization so I'd be slightly wary of label=. I'm pretty solidly > against renderSimpleForm() but I can't argue very convincingly against > renderFormField() (at the moment! :) Yes, label is "friendly name" -- localization is a great issue. I guess it seems like someone who is building a multi-lingual site will need to find an alternative way if they want some generic form generation to happen (or submit changes to Modus that allow it ;). This is a great example of the different perspective -- working on macromedia.com you are forced to think about things like localization, whereas I have not dealt with it very much. I think it's safe to say that the "label" mechanism in the descriptor is not a requirement and not something that a lot of "advanced" sites would use (like most advanced CF developers would never touch CFINSERT/CFUPDATE and most would not use client variables, but those are handy features of the language for a newbie -- I see renderSimpleForm() in the same category). |
From: Nathan D. <na...@ch...> - 2002-11-01 23:57:38
|
I guess I'd rather not have baseContentObject know whether a field is a contentObject collection or not -- it just seems cleaner to have a field type that knows how to deal with it. That is, I don't think it makes sense to abstract "collections" from "fields" -- if a field is a collection that is the business of the field implementation. Make sense? Am I missing obvious pitfalls to that? I absolutely agree that linked components should have to deal with their own persistence/editing. I think that even in renderSimpleForm() all you would see is a SELECT that have the id's of the linked fields -- I don't think for 1.0 we should spend any energy trying to "edit a collection as a collection" (or render it as such) as you suggest. -----Original Message----- From: mod...@li... [mailto:mod...@li...]On Behalf Of Jeremy Firsenbaum Sent: Friday, November 01, 2002 2:41 PM To: mod...@li... Subject: Re: [Modus-devs] XML descriptor of linked contentObjects, WAS: Collections of content objects and performance I think most of the code that I added to basecontentobject to support the objectArray type can be used for the collection implementation. In fact, the field type should be easy in comparison. Correct me if I'm wrong but it looks like adding one conditional to addField() and getField() in basecontentobject to check for field type would make this work: For example, from addField line 422: if it's a simple value do thisField.setAttributes(arguments); if it's a collection do //collectionAdd() was objectArrayAdd() collection = this.collectionAdd(arguments.name, arguments.collectionType, arguments.key) thisField.setCollection(collection); I haven't tested this, but if it seems like I'm on the right track I'd be happy to try it out over the weekend. Another thought is that I don't see supporting persistence for collections. I can't imagine needing to edit a collection as a collection. It would be much simpler to make the persistence calls on individual collection items. For example: post = forums.getCollectionItem('posts', 3) //make some changes to post, then do post.store() How's that sound? |
From: Sean A C. <se...@co...> - 2002-11-01 23:41:39
|
On Friday, Nov 1, 2002, at 08:46 US/Pacific, Nathan Dintenfass wrote: > Let me say first that Modus is not intended to be a general application > framework -- it is focused on building web-delivered applications > written in > CFML. Given the intended use of Modus, the "80% case" is the target > for the > code base (particularly for 1.0). OK, but it sounds like it's intended to be "more general" than 'just' a persistence mechanism which is part of what I'm really trying to get a handle on. > I come from a viewpoint that speed of > development for a CFML developer wanting to build web pages that > deliver > dynamic content is a key consideration that, in my mind, may trump > certain > design philosophies. Agreed. And performance is probably a higher goal than 'sweet design under the hood'. Take Fusebox as an example. > For me, the > modustest app in its current form is a living proof-of-concept that > demonstrates how very very easy it is for someone to very rapidly > create a > very simple CMS. Agreed, but it's not very fast, I gather :) > As we move towards linked contentObjects and other > "advanced" features I don't want to lose such ease of use for the base > case. Agreed. I'm actually trying to ensure that we don't try to build in features that make Modus complicated to use or make it terribly slow to run. I would avoid embedded components for those very reasons. > A lot of the discussion in the last 24 hours has started to revolve > around > what a field is and what the descriptor should know. These are both > good > discussions to have, particularly as we prepare to rewrite the guts to > use > the XML descriptor. Agreed. Can I put in a little vote for making the presentation specifications optional? And having the renderXxx() method(s) throw an exception if an attempt is made to render an object for which no specification is given... > The renderSimpleForm() is just a convenience that I think will move > out of > the baseContentObject and into some kind of contentObjectUtility. I think a field can render itself but I'm not sold on the idea of a whole object rendering itself as HTML... > I can just > call renderFormField() on that field and get the proper HTML input. Yes, I think that's reasonable (given my caveat about optional presentation specs). > I could be much more easily convinced to do away with "label" and > renderSimpleForm() than I could to not have fields know how to create > the > proper HTML form widget for themselves. But, it sure is handy to have > that > label ;) I think 'friendly name' is a good concept but it doesn't lend itself to localization so I'd be slightly wary of label=. I'm pretty solidly against renderSimpleForm() but I can't argue very convincingly against renderFormField() (at the moment! :) > On the subject of embedded vs. reference for linked components: I tend > to > lean towards references. Although embedded can have some advantages, > it > will likely prove to be overly cumbersome from a performance > standpoint (and > from a code sanity standpoint). Agreed. I'd be perfectly happy to not support embedded subcomponents - it certainly didn't help us much (it actually caused us more problems than it solved). We need to be careful about the array issue for similar reasons. Simple enough for the audience without allowing them to hang themselves on poor performance. "Conform! Consume! Obey!" -- Mr Snaffleburger : http://www.matazone.co.uk/theotherside.html |
From: Jeremy F. <jfi...@ma...> - 2002-11-01 22:41:12
|
I think most of the code that I added to basecontentobject to support = the objectArray type can be used for the collection implementation. In = fact, the field type should be easy in comparison. Correct me if I'm wrong but it looks like adding one conditional to = addField() and getField() in basecontentobject to check for field type = would make this work: For example, from addField line 422: if it's a simple value do thisField.setAttributes(arguments); if it's a collection do //collectionAdd() was objectArrayAdd() collection =3D this.collectionAdd(arguments.name, = arguments.collectionType, arguments.key) thisField.setCollection(collection); I haven't tested this, but if it seems like I'm on the right track I'd = be happy to try it out over the weekend. Another thought is that I don't see supporting persistence for = collections. I can't imagine needing to edit a collection as a = collection. It would be much simpler to make the persistence calls on = individual collection items.=20 For example:=20 post =3D forums.getCollectionItem('posts', 3) //make some changes to post, then do =20 post.store() How's that sound? ----- Original Message -----=20 From: Nathan Dintenfass=20 To: mod...@li...=20 Sent: Friday, November 01, 2002 3:59 PM Subject: RE: [Modus-devs] XML descriptor of linked contentObjects, = WAS: Collections of content objects and performance > Right, but how many 'collection' implementations will you have? Just > one in general I suspect so the type=3D"..." could be implicit and = the > whole field spec would be simpler. Just a thought. Yes, I suppose that's true. Though, that would mean internally when a contentObject was initializing it would have to do some kind of meta = data discovery to determine if the field it was using was, in fact, another content object -- that seems messier than just having the end user say = to use the contentObjectCollection field type and pass in what kind of = content object. I can easily imagine someone extending = contentObjectCollection to do some specialized things, so it would be good to have the descriptor semantics reflect this -- and that is consistent with how all other = fields work (except that most field types don't need extra configuration information). I guess that until I (or someone else?) actually sits down to = implement the contentObjectCollection field type this is all academic, but given the = way Modus works today that is what makes the most sense to me. Agreed? - n ------------------------------------------------------- This sf.net email is sponsored by: See the NEW Palm=20 Tungsten T handheld. Power & Color in a compact size! http://ads.sourceforge.net/cgi-bin/redirect.pl?palm0001en _______________________________________________ Modus-devs mailing list Mod...@li... https://lists.sourceforge.net/lists/listinfo/modus-devs |
From: Nathan D. <na...@ch...> - 2002-11-01 22:24:19
|
> On Friday, Nov 1, 2002, at 09:37 US/Pacific, Nathan Dintenfass wrote: > > Well, once again the nature of "field" is the issue here. The yesno > > field > > exists because to just say "this is a boolean" value does not seem to > > have > > any advantage of just defining a column in a table in a database. > > OK, I see where you're coming from... And I can see that yes/no is more > familiar to CFers (although I resolutely use true/false :) Actually, if memory serves, the yesno field uses 'true' and 'false' as the values it persists. The way to think about it is that rather than needing to take the step of defining a datatype and then building the display and form widget separately, a "field" in Modus can wrap these two together. While this can be seen as breaking the barrier between data and logic and display, it does work rather well in the finite universe Modus inhabits -- web-delivered applications built in CFML. Given that MOST of the time when you want to store some text you'll use INPUT type="text" and MOST of the time you want a boolean you'll show the user a yes/no radio choice, etc. it seems reasonable to just go ahead and encapsulate that for the developer. Yes, it's breaking "the rules", but it's doing so with eyes open for (what I hope are) good reasons. > I guess I'm just concerned about the overhead in such 'rich' fields, as > opposed to just trying to persist an 'object'. As long as Modus can > still persist a simple boolean, as well as your yesno, then I'm happy. Again, the yesno "field" just stores a "boolean" data chunk. I just remove the need for the developer to have to define both of them. As always, though, I am very open to suggestions. Modus is a learning experience for me more than it is an expression of what I think of as "the right way." > I think it's reasonable to have some fields that are self-validating > and this 'rich' yesno field seems to be a good candidate. Ah, good. Should it be smart enough to not run the same rule twice if the developer DOES specify it? I suppose so. - n |