> I'm the sort of person who likes to understand why I'm
> doing something rather than just do it. If I download
> a UDF I analyse it and try to learn rather than just
> stick it into my app and smile because it's worked.
> With that in mind, I wonder if someone could explain
> to me in super simple, beginer speak, layman terms
> what Object Oriented Programming means in terms
> of CF and why I should use it?
OO Programming in terms of CF means what it does in every other
language: that you have Classes ("static" methods of which can be
executed in CF using <cfinvoke component="my.component.path"
method="mymethod"> although I don't recommend this because the CF
server creates an object anyway) and Objects (which are created when
you use CreateObject() or <cfobject> to "instantiate" a CFC). There's
no magical connection between OO or OO-ness and frameworks like
Model-Glue or Mach-II -- they are no more or less OO frameworks than
any other framework except possibly with respect to the framework's
underlying guts (the part that most framework implementers never
touch) may be written as CFC's instead of procedural templates. In the
final analysis, however, this distinction of the guts of the framework
being written with Objects/OO or being written with procedural code
makes not one iota of difference to you, unless you yourself are
modifying the framework (i.e. creating a derivative framework) which
is not something most people do.
> My very basic understanding is that you have different
> 'layers' to perform different tasks, so when someone
> visits mygroovyform.cfm the processing behind the form
> is not done on the form page itself but passed to another
> page which then passes back the results. The back end
> processing is then done using components (cfc's).
Asside from the mention of CFCs at the end, this paragraph really
doesn't describe OO, it describes Model-View-Controller (MVC) or
something like it. I say asside from the mention of CFC's because it's
not necessary to use them (or OO/Objects) to implement an MVC
application. MVC is more like a "best practice" -- it's not a
framework because it doesn't include any specific, pre-written code,
it's merely a loose description of a good idea about how to abstract
an application so that it will be easier to expand upon that
application later. (Easier expansion is a benefit of having minimized
any interdependancies between the Model (business logic) and the View
(html, text, pdf, mobile devices, etc). The Controller is just a
concept for an intermediary between these two layers which helps in
the reduction of dependancies between them... I.e. it's sometimes
easier to eliminate dependancies between the view and the model if
they both assume that a 3rd entity (the controller) will ensure that
communication between them is accurate. This way the view can simply
assume that query-a exists, without needing to reference the model to
retrieve it, and the model can simply assume that whatever data it's
asked to provide will be appropriately used later on. Thus the
controller then becomes primarily responsible for creating the end
result by knowing that when the user requests the "orderDetail" page,
it must fetch the query from the model and include the appropriate
view.
> I know that's a very simplified explanation but hopefully
> it's true in principle. I've written a few very simple
> CFC's more for the sake of it than because I understood
> the need. The main arguments I've heard for using this
> approach is that it's good for code re-use and promotes
> clean coding. But what I can't get my head around is why?
> I mean, code isn't necessarily unclean because it's not
> built using this approach and can't code just as easily
> be reused using a cfmodule or even a cfinclude?
In some cases, yes, good clean code can be equally created using other
techniques like cfmodule, cfinclude or by loading function libraries.
In other cases, having "instance data" can really help to create more
legible (i.e. cleaner) syntax and/or more modular/flexible tools.
Here's a good example:
I had a sql-abstraction layer in my framework. Had it for a while,
originally written on CF5 (or at least written to support CF5).
Started out with a series of custom tags (cfmodule):
<cfmodule template="#request.tapi.db.select()#"
table="mytable" return="rs">
<cfmodule template="#request.tapi.db.filter()#"
column="x" content="#attributes.x#" />
<cfmodule template="#request.tapi.db.filter()#"
column="y" content="#attributes.y#" />
</cfmodule>
Now this block of code would replace this query:
<cfquery name="rs" datasource="primary" username="..." password="...">
select * from mytable
where x = <cfqueryparam value="#attributes.x#"
cfsqltype="cf_sql_integer">
and y = <cfqueryparam value="#attributes.y#"
cfsqltype="cf_sql_integer">
</cfquery>
Sorry for the line-wrap... anyway it's fairly obvious that there's no
keystroke savings here, and in all honesty, the cfmodule tags make it
a bit more complicated (harder to read), but I was willing to put up
with that because where SQL is inconsistent across databases, these
tags were consistent. Later I created some MX only functions to wrap
around these tags and they looked like this:
<cfset rs = request.tapi.sql.select("mytable","*","",
request.tapi.sql.filter("x",attributes.x,
request.tapi.sql.filter("y",attributes.y,"","="),"="))>
And while this syntax saved me some keystrokes it wasn't any more
legible. In fact it might have even been harder to read, since now you
had to nest your filters in this quirky way (and filter and join
statements had to be intermingled, and they were intermingled with the
other arguments of the select function, etc.)
Finally when I decided to stop supporting CF5 I reinvented the SQL
abstraction with objects. The addition of instance data makes the
syntax _MUCH_ more legible and therefore much more maintainable:
<cfset statement = datasource.getStatement("select")>
<cfset statement.filter("x",attributes.x).filter("y",attributes.y)>
<cfset rs = statement.execute()>
Plus, this syntax does indeed make the SQL abstraction API more
flexible. A couple of exmaples: I'm now able to reference
statement.getSyntax() to return a string representation of the query
without any duplicated code. Statements can have listeners which are
notified when the statement is executed. In the case of select
statements, these listeners can act as filters on the returned query,
which as a result allows me to use a factory object to return a query
that can be sorted on data which is _not_ stored in the database.
<cfset search = request.tap.memberFactory.getSearchStatement()>
<cfset rsMember = search.sort("language").execute()>
Now, the names of languages is not stored in the database -- why?
Because the names of languages vary -- French when written in French
is Francais, German is Deutsch (yeah, I know, I'm butchering them, but
you get the idea). So the names of languages are provided by Java
instead of from the database. This means the database can't perform
any sorting on the language column. But ColdFusion can! Now, within
the page containing the code above that fetches the searchStatement
from my factory it isn't necessary to know that the language names
come from Java or that they won't be sorted by the databse -- it's
only necessary to know that when you search.sort("language").execute()
that the query result will be sorted by the content of that column
just like it would for any other column. This eliminates any need on
my part to provide extra sorting features which would be applied in
the page, since I know the factory will provide this feature
automatically. If I were still using custom tags or functions I would
need to either write an extra sorting routine in the page, or I would
need to write a separate wrapper tag / function for searching the
member database. You might say that getSearchStatement() is a wrapper
-- in a way it is, but it's much more flexible than wrappers written
with cfmodule or functions (without instance data), since instead of
wrapping the run-time feature (fetching the query) it only wraps the
creation of an instance of a predefined class (a select object) and
sets its parameters prior to execution.
> I've also heard it's good in a multi-developer
> environment, but I'm only me so perhaps there
> isn't a practical reason for me to learn it at all?
See above. :) I'm not saying you _will_ find a use for it, but once
you have a deeper understanding of the fundamentals of OO/CFCs and
"instance data" there's a good chance you might start to see new doors
opened. I'm a strong believer in the "right tool for the job"
philosophy.
> I've read a lot on the subject and I'd like to read more
> but it's difficult to enthuse myself without understanding
> what the real end benefit is.
> <scratches_head>Model glue, mach ii, fusebox, etc. I'm
> sure there's a bloody good reason for 'em but what
> is it?</scratches_head>
The reasons for these is very different from the reasons for OO
actually... As I said, they're not really related. Mach-II and
Model-Glue are referred to as "OO Frameworks" more because people have
come to expect the term "OO" to be used to describe anything of value,
whether it's related to OO or not. Mach-II (and possibly Model-Glue,
I'm not sure) attempt to force the users to use CFCs for business
logic. I don't personally find this to be especially helpful, not
because I feel CFCs are a bad choice for model components / business
logic, but because it's not more than organizing those components (via
XML config) and in theory preventing bonehead noobs from making the
"mistake" of not using CFCs for a particular task. Personally I find
it much more valuable to focus on increasing the productivity of
people who know what their doing (rather than focusing on trying to
protect the code from inexperienced people) and I don't need XML to
organize my CFCs.
I use CFCs a lot actually, I just don't like using XML to configure my
applications, and generally find that even if I did want to use XML
for configuration, the syntax for doing so with Fusebox, Mach-II and
Model-Glue are all more verbose than I prefer. I'd much rather the
framework make some basic assumptions (default values) the same way
that the ColdFusion server saves me headaches by providing common
default values with its tags. If the ColdFusion server were written
the way that these frameworks have been written, there would probably
not be a port default in the cfpop, cfmail, cfhttp or cfftp tags, and
they'd describe it as a "feature" that makes the application easier to
understand. :P
I won't say that the onTap framework is the easiest thing in the world
to understand. It certainly reduces the amount of code I write (by
orders of magnitude actually). But then I also don't market it as an
"OO Framework" -- I market it as being OO agnostic (with gads and gads
of code-reuse and general "make life easier" tools in its various
API's). Use OO techniques if you want, skip them if you don't. Though
some of its most impressive features/API's happen to be OO driven
(SQL-Abstraction and the RuleManager facade, both of which I'll be
speaking about at the cf.Objective conference this weekend).
I'm not sure about books -- I'm sure others will recommend several.
And I'm sure the phrase "gang of four" will be bandied about. Whether
that's a good thing or not I couldn't say. :) May not need anything
that serious to start with... Wikipedia's got some good information
about tech terms like MVC.
s. isaac dealey 434.293.6201
new epoch : isn't it time for a change?
add features without fixtures with
the onTap open source framework
http://www.fusiontap.com
http://coldfusion.sys-con.com/author/4806Dealey.htm
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
Message: http://www.houseoffusion.com/lists.cfm/link=i:4:234345
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