> Isaac, you've given me an answer for something I'd given
> up on, I wrap my
> SPs in functions some of the time, but because I don't
> want to call the SP
> twice on one page I've always assigned to a local variable
> and then accessed
> the resultset via that variable. For example:
> <cfset qUser = GetUser(userID)>
> <cfoutput>
> #qUser.Username#
> #qUser.Email#
> </cfoutput>
> What I would rather do, and this is purely for aesthetic
> reasons on my part,
> is this:
> <cfoutput>
> #GetUser(userID).Username#
> #GetUser(userID).Email#
> </cfoutput>
> And using your example of checking in the VARIABLES scope
> for the recordset
> before calling the SP I can do that without two or more
> calls to the DB.
Glad I could help...
Although my own CFC's tend to look a bit different... I'd have
probably actually used a "user" CFC for the login and called it like
this (again, pseudocode):
<cfset user = createObject("user").init(userid)>
<cfoutput>
#user.getProperty("username")#
#user.getProeprty("email")#
</cfoutput>
In this setup, my init() function would clear all properties of the
object (<cfset structclear(variables.properties)>) then check to make
sure the userid is valid (exists in the database) and if the userid is
valid then it would initialize some identifying variables for the user
or maybe go and get property data for persistent storage if I happen
to be using a DAO type system. I tend not to go and fetch all the
object data at once, particularly if the object happens to have a lot
of data and/or a lot of calculations involved in its data and instead
resort to incrementally caching the object data within the object when
it's requested.
For a moment, looking at the variable name "getUser" I was thinking
this was a CFC designed specifically for a login page, but now I'm
thinking not... GetUser just contains methods that get data from the
db based on a userid for reporting purposes? ... seems like an odd
abtraction, but that's my best guess...
> However, now I've thought about it, I'm beginning to
> favour the former. How's that for fickleness?!
:) We all got our quirks.
> Yes, but, you do need to know the public interface of an
> object which includes what it returns if anything. So for
> this example you need to know that putting the car in
> reverse and hitting the gas will back the car up. You
> could argue that knowing exactly what a function returns
> has no baring on it being less black boxed, regardless of
> it being a resultset, or a struct of queries. At what
> point does it become too open:
> - you know it returns a structure?
> - you know it returns a structure with a key of
> myResultset?
> - you know it returns a structure with a key that
> references a query?
> - you know it returns a structure with a key that
> references a query that
> has a column UserID?
> I don't have a firm opinion on this, but if it's not the
> first line then I don't think it would be anything other
> than the last.
This is true -- although I think the general thinking (and don't quote
me, because I'm just sort of passing on what I think I've heard/read
here) is that the more complex the result of the function is, the less
cohesive and therefore less generally useful the method is. In other
words, if I create a method that returns several queries in a
structure along with some associated string and array values, the
likelyhood that all that data will be valid and useful in more than
one place is not very high. Granted, in this instance we're only
talking about a structure that contains two queries, so it's nothing
that complicated, but the _theory_ says essentially that "less is
more".
As an example, I have a cfc I'm working on where I work now which has
a couple functions in it like this (and please, no critiques -- I'm
putting lipstick on a pig as it is with this application):
<cffunction name="getCommissionTypes"
access="public" returntype="string" output="false"
hint="returns a comma delimited list of commission type codes">
<cfreturn "IBA,IBB,OBB,RBB">
</cffunction>
<cffunction name="describeCommission"
access="public" returntype="string" output="false"
hint="returns a human readable description for a given commission
type">
<cfargument name="ctype" type="string" required="true">
<cfswitch expression="#ctype#">
<cfcase value="IBA"><cfset ctype = "In House Agent"></cfcase>
<cfcase value="IBB"><cfset ctype = "In House Broker"></cfcase>
<cfcase value="OBB"><cfset ctype = "Outside Broker"></cfcase>
<cfcase value="RBB"><cfset ctype = "Referring Broker"></cfcase>
</cfswitch>
<cfreturn ctype>
</cffunction>
One of the alternatives to this that I considered was simply having a
single function which would return a structure containing the
descriptions with the commission type codes as their keys. I decided
against it because there are actually a number of circumstances in
which it's useful to have a list of the commission types without
necessarily needing the human-readable names, and rather than return a
structure it's likely easier for everyone just to quickly get a comma
delimited list and a split infnitive. You could argue that the list
would still have been available in the results from the function that
returns just a structure, but if they're not necessary then returning
them is just going to confuse the issue. Cohesion cohesion cohesion.
> "In a lot of cases we do end up returning structures from
> functions,
> but in general my thinking is that if it's possible to
> return a
> structure, then in most cases, particularly when the
> content of the
> structure is varied and complex such as queries, there
> should also be
> a consistent syntax to produce any of the individual
> values in that
> structure independent of the structure itself, whether
> that's
> getNameOfStructureKey() or
> getProperty("nameOfStructureKey") (my
> preference). At this point the function which returns the
> structure is
> merely a convenience afforded for the sake of processes
> which utilize
> a large amount of the returned data at once, rather than
> needing only
> certain discrete bits of it."
> I see your point with this. Better to have:
> #user.getProperty("username")#
> #user.getProperty("password")#
> #user.getProperty("email")#
> than:
> #user.getUsername()#
> #user.getPassword()#
> #user.getEmail()#
> as a way of dealing with structures or queries. The former
> could deal with
> ever increasing/decreasing resultset rows, add a new
> column,
> user.getProperty("hairColour"), take a column away and you
> don't have
> redundant methods that need removing. But, if you know the
> name of a struct
> key/query column, what's wrong with using it directly
> without going through
> a method, getProperty("someKeyOrColumn")? Ok, it is more
> encapulated, but
> there are ways around it that I wouldn't consider to be
> too much work to
> implement.
My reason for using this method has to do with spontaneous needs for
special handling. That is to say, if I have a particular CFC and I
make a custom version of that component for a client which extends the
original CFC and that client needs a given property to be handled in a
manner that is unique only to that client, then if I've used variables
in the "this" scope, I'm pretty much shit out of luck because that
means I have to tear through my entire application to find any
possible place where that variable is referenced to apply the special
handling rules -- which is ultimately much of what CFC's or for that
matter custom tags and functions and even gosh-darn-it, cfinclude were
designed to help alleviate in the first place.
So this is the reason that a lot of programmers advocate the accessor
functions, the getPropertyX(), setPropertyX() because then you always
have a place where you can implement any special handling needed for
that property. My problem with that approach (and part of the reason I
dislike beans) is that it requires a separate function for each
property even when no special handling is required and that's why when
I implemented my cfc's I used the getProperty("nameofproperty") syntax
so that I only need to write a function to handle the special handling
_IF_ special handling is needed.
I'm told that this flies in the face of introspection, but honestly, I
think it's _more_ informative because I already have the names of all
my properties, I already know what I can get and set, I don't need the
existence of the function to tell me that -- but if I only have the
function if there happens to be special handling, then I know exactly
how many of my properties actually require special handling and which
ones from looking at the methods in the CFC.
> If you start off with returning a query and all code that
> accesses it uses
> query.column you could always maintain the returning of a
> query even if it
> changes to something else. If they had a query to begin
> with, give a query
> even when it's actually a structure/array/simple value.
You're talking about the back-end data underneath the CFC -- yes, this
is true... I'm not certain exactly how this ties into the rest of your
comments tho... so I'm a tad puzzled.
> I do like the getProperty() idea.
Glad you like it. :) I've had the whole range of comments about it
from, "you awful bastard" to "that's clever" and everything in
between, I think mostly including "say what?".
> Anyway, it's 01:30 and my bed looks very inviting. Sorry
> if my ramblings
> seem to contradict each other that's probably because they
> do! And d'you
> know what I like about Isaac's and Jared's posts? They
> don't in any way seem
> preachy. Which to me makes them damn fine posts :O)
Well I try. :) Maintaining some semblance of humility ranges from
incredibly easy to sometimes actually somewhat difficult... it varries
from day to day depending on what I've been doing and who's been
stroking my... ego. :) (The elipses was supposed to be a dramatic
pause, you wierdo!)
Though in general I like to think I'm much more likely to brag about
my accomplishments (like the new and/or keyword filters features in
the framework so german users can get all glidden products in the
paint category by entering "glidden und paint" in the search form),
than I am to tell people they need to emulate my coding habbits...
There are a very few coding habbits I would actually describe as evil,
but that's more a matter of asking people not to make my life harder
than it has to be if I end up working on a project after them than it
is trying to preach. :P
Hey, I never said I wasn't long-winded. :)
s. isaac dealey 954.522.6080
new epoch : isn't it time for a change?
add features without fixtures with
the onTap open source framework
http://macromedia.breezecentral.com/p49777853/
http://www.sys-con.com/story/?storyid=44477&DE=1
http://www.sys-con.com/story/?storyid=45569&DE=1
http://www.fusiontap.com
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
Logware (www.logware.us): a new and convenient web-based time tracking
application. Start tracking and documenting hours spent on a project or with a
client with Logware today. Try it for free with a 15 day trial account.
http://www.houseoffusion.com/banners/view.cfm?bannerid=67
Message: http://www.houseoffusion.com/lists.cfm/link=i:4:197560
Archives: http://www.houseoffusion.com/cf_lists/threads.cfm/4
Subscription: http://www.houseoffusion.com/lists.cfm/link=s:4
Unsubscribe: http://www.houseoffusion.com/cf_lists/unsubscribe.cfm?user=89.70.4
Donations & Support: http://www.houseoffusion.com/tiny.cfm/54