Transcript Slide 1

About Me
Explosive Ordnance Disposal
About Me
Technically Speaking…
• SQL (MSSQL, Sybase, Oracle, Access)
• ColdFusion
– OOP/CFCs
– Webservices
– Ajax
– Model-Glue
– Coldspring
(www.dougboude.com/blog)
• JavaScript
• Visual Basic
What I’ll be Talking About
• OOP Essentials
• Adding to your personal Lexicon
• Learning to see what is invisible
What I’ll NOT be Talking About
Why OO in the first place?
• Code Segregation and logic isolation /
encapsulation
• Reduced Development Time
• Code Re-Use
• Job Security/opportunities
CFCs as Objects
• A coldfusion ‘object’ is simply a persistent
instance of a CFC.
This…
<CFINVOKE
component="model.user"
method="getUser"
returnvariable="stUser"
argumentcollection=“stArgs" />
As opposed to…
<CFSET objUser = CreateObject("component","model.user") />
<cfset stUser = objUser.getUser(argumentCollection = stArgs) />
CFCs as Objects
SCOPE within a CFC
• THIS – visible internally and externally to the CFC
Within the component…
<cfset this.GlobalVal = “See me now?” />
Within our calling template…
<cfscript>
myTestObj = CreateObject(“component”,”myTest”);
myTestObj.GlobalVal = “I set you from outside of the object!”;
</cfscript>
• Variables
• Var
CFCs as Objects
SCOPE within a CFC
• THIS
• Variables – available to any method within the CFC, but not directly
visible externally
<cfset variables.internalValue = "See me now?" />
<cffunction access="public" name="sampleMethod" output="false"
returntype="string">
<cfreturn variables.internalValue />
</cffunction>
• Var
CFCs as Objects
SCOPE within a CFC
• THIS
• Variables
• Var – Ensures that a variable will be available local to the method, and
thread safe
<cffunction access="public" name="sampleMethod" output="false"
returntype="void">
<cfargument name="sourceID" type="numeric" required="yes“/>
<cfset var iterations = 0/>
<cfset var urlitems = "“/>
<cfset var newInsertItems = arraynew(1)/>
</cffunction>
CFCs as Objects
Constructors
• Typically named ‘INIT’
• Used for the same reasons we use
application.cfm/cfc or an app_globals.cfm file
• Always should return ‘This’
<cffunction access="public" name="init" output="false"
returntype="COM.RSS">
<cfargument name="dsn" type="string" required="yes" default="">
<cfset variables.dsn = arguments.dsn>
<cfreturn this>
</cffunction>
<!--- take note of returntype and access values… --->
CFCs as Objects
CFPROPERTY Tag
• Used for informational purposes only…no
functional value.
• Webservices will read them;
• Some CFC Documenters will read them
CFCs as Objects
Anatomy of an Object
• Has properties (static values, such as DSN)
• Can ‘DO’ things (has methods that can be
called)
That’s it.
CFCs as Objects
When Objects Use Objects!
The CFC content…
<cffunction access="public" name="init" output="false" returntype=“model.userService">
<cfargument name="dsn" type="string" required="yes" default="">
<cfset variables.dsn = arguments.dsn />
<cfset variables.objUser = CreateObject("component","model.user") />
<cfset variables.objAddress = CreateObject("component","model.address") />
<cfreturn this />
</cffunction>
<cffunction name="insertUser" access="public" output="false" returntype=“void">
<cfargument name="firstname" type="string" required="true" />
<cfargument name="address1" type="string" required="true" />
<cfset var userid = "" />
<cfset var addressid = "" />
<cfset userid = variables.objUser.insertUser(firstname=arguments.firstname,
DSN=variables.DSN) />
<cfset addressid = variables.objAddress.insertAddress(userid = userid, address1 =
arguments.address1, DSN=variables.DSN) />
</cffunction>
CFCs as Objects
When Objects Use Objects!
Calling the CFC…
<!--- Instantiate the userService object...note that we're calling INIT upon instantiation and
passing in our DSN value from a persistent scope --->
<cfset objUserService = CreateObject("component","model.userService").init(DSN =
application.dsn) />
<!--- make our call to the insertUser method. insertUser returns ‘void’, so we don’t set the call
equal to any variable. --->
<cfset objUserService.insertUser(firstname = "Doug Boude", address1 = "109 Main St") />
Adding to Your Personal Lexicon…
Method
Injection
Event-Handler
Mutator
Transfer
Object
ViewStack
DAO
Accessor
Controller
Listener
Service
Layer
Scaffolding
Model
Message
Implicit
Invocation
Event
Broadcast
ViewState
Auto-Wiring
Adding to Your Personal Lexicon…
Just a few…
•Abstraction
•Façade
•Service Layer
•Model
•View
•Controller
Doug Boude’s Personal OO Lexicon:
http://www.dougboude.com/documents/dougboudeslexicon.cfm
Or
Go to www.dougboude.com and search for ‘lexicon’
Adding to Your Personal Lexicon…
Service Layer
BREAK POINT
(Time for Model-Glue!)
Model-Glue: Unity
• What is this trinity?
– Model-Glue
– Reactor
– Coldspring
• Where does it live?
– Anywhere globally accessible. One instance
of the framework drives N apps
Model-Glue: Unity
Typical Model-Glue Application
directory Structure
Model-Glue: Unity
Configuration
• Application.cfc
– For me and my team, we typically only use this to name the app, not
much else.
• Coldspring.xml
– Where a lot of the meaty app config takes place. Coldspring manages
objects…ModelGlue is an object…so here is where we configure our
“model glue bean”.
• ModelGlue.xml
– The heart and soul of your application. Equate it with the index file in
Fusebox 2, or the CF_Switch file in FB3.
• Reactor.xml
– Reactor manages relationships among your backend data tables.
Configure those relationships here if you opt to use Reactor.
Model-Glue: Unity
COLDSPRING.XML SNIPPET…
<beans>
<!-- This is your Model-Glue configuration -->
<bean id="modelGlueConfiguration" class="modelglue.unity.framework.ModelGlueConfiguration">
<!-- Be sure to change reload to false when you go to production! -->
<property name="reload"><value>true</value></property>
<property name="rescaffold"><value>false</value></property>
<!-- Be sure to change debug to false when you go to production! -->
<property name="debug"><value>false</value></property>
<property name="defaultEvent"><value>page.home</value></property>
<property name="reloadPassword"><value>true</value></property>
<property name="viewMappings"><value>/views</value></property>
<property name="generatedViewMapping"><value>/views/generated</value></property>
<property name="configurationPath"><value>/config/ModelGlue.xml</value></property>
<property name="scaffoldPath"><value>/config/scaffolds/Scaffolds.xml</value></property>
<property name="statePrecedence"><value>form</value></property>
<property name="reloadKey"><value>init</value></property>
<property name="eventValue"><value>event</value></property>
<property name="defaultTemplate"><value>index.cfm</value></property>
<property name="defaultExceptionHandler"><value>exception</value></property>
<property name="defaultCacheTimeout"><value>5</value></property>
<property name="defaultScaffolds"><value>list,edit,view,commit,delete</value></property>
</bean>
Model-Glue: Unity
REACTOR.XML SNIPPET…
<objects>
<object name="User">
<hasMany name="UserOrganization">
<relate from="UserId" to="UserId" />
</hasMany>
</object>
<object name="UserOrganization">
<hasOne name="user">
<relate from="userId" to="userId" />
</hasOne>
<hasOne name="Organization" >
<relate from="OrganizationId" to="OrganizationId" />
</hasOne>
</object>
<object name="Organization" >
<hasMany name="User">
<link name="UserOrganization" />
</hasMany>
</object>
</objects>
Model-Glue: Unity
<modelglue>
<controllers>
<controller name="AuthenticationController" type="controller.AuthenticationController">
<message-listener message="OnRequestStart" function="SetCurrentUser" />
<message-listener message="Logout" function="logoutUser" />
<message-listener message="Login" function="authenticateUser" />
</controller>
</controllers>
<event-handlers>
<event-handler name="user.login">
<broadcasts>
<message name="Login" />
</broadcasts>
<views>
<include name="personalInfo" template="dspPersonalInfo.cfm" />
<include name="body" template="dspLanding.cfm" />
</views>
<results>
<result name="valid" do="user.loggedin" redirect="true" />
<result name="invalid" do="page.home" redirect="true" />
</results>
</event-handler>
</event-handlers>
</modelglue>
Model-Glue: Unity
Modes of Operation
• Development
• Production
In order to toggle between development and production
modes, edit the "reload" property in Coldspring.xml,
setting the value to "true" for development or "false" for
production. In addition, edit the "debug" property, setting
the value to "true" for development or "false" for
production.
Model-Glue: Unity
MAKING CHANGES DURING DEVELOPMENT
Because MG:Unity maintains some objects in persistent scopes like Application
and Session, certain types of changes made during development require
certain actions in order to see those changes.
If you make a change to:
• ModelGlue.xml - Make sure the "reload" property in Coldspring.xml has a
value of "true"; initialize the app by going to the url [app url]/?init=true
• Coldspring.XML - If reload=true, then there's nothing to do; otherwise, set
reload=true, then add init=true parameter to the url
(www.myapp.com/index.cfm?init=true)
• a controller cfc - same as above
• a model cfc - all changes should be visible real time...nothing to do
• database - Reactor needs reset. In Coldspring.XML, in the Reactor Bean,
make sure mode is development and make sure reload=true. if
reload=false, follow steps for Coldspring.xml changes.
Model-Glue: Unity
Seeing What is Invisible:
Visualizing the Model-Glue Event Lifecycle
Web page
Model-Glue: Unity
Visualizing the Model-Glue Event Lifecycle
(index.cfm?event=user.login)
ModelGlue.XML
1. A request is made!
MG
FRAMEWORK
<modelglue>
<event-handlers>
<event-handler name="user.login">
<broadcasts>
<message name="Login" />
</broadcasts>
…
</event-handler>
</event-handlers>
</modelglue>
2. MG Framework reads the description of the
requested event.
Event bucket is created and Incoming variables
(URL, FORM) are placed into it.
Messages are broadcast as defined by the xml…
Event
Model-Glue: Unity
Visualizing the Model-Glue Event Lifecycle
Controller “hears” the ‘login’
message being broadcast…
ModelGlue.XML
<modelglue>
<controllers>
Controller
CFC
3. Listening controller
message…
<controller name=“UserController"
type="controller.UserController">
<message-listener message="Logout"
function="logoutUser" />
<message-listener message="Login"
function=“UserLogin" />
</controller>
</controllers>
executes
the method
</modelglue>
associated with the
Any Results, data, or other relevant information
resulting from the method execution is placed into the
event bucket…
Event bucket is passed back to the framework.
Event
Model-Glue: Unity
Visualizing the Model-Glue Event Lifecycle
Event
Event bucket passed back from the
controller to MG…
ModelGlue.XML
MG
FRAMEWORK
<modelglue>
<event-handlers>
<event-handler name="user.login">
<results>
<result name="valid" do="user.loggedin" />
<result name="invalid" do="page.home" />
</results>
…
</event-handler>
</event-handlers>
</modelglue>
4. Any relevant ‘Results’ value
placed into the event bucket by the
controller are evaluated and events
are called as appropriate.
If there are no relevant ‘Results’, any
(in this way, you can “chain”
defined Views for that event are then
events…)
evaluated…
Model-Glue: Unity
Visualizing the Model-Glue Event Lifecycle
Web page
PersonalInfo
5. The views defined in the
<VIEWS> tag are rendered by
MG and returned to the browser
body
#PersonalInfo#
(This stack of rendered views is
called the Viewstack)
ViewState
MG
FRAMEWORK
Values needed for display purposes
are gotten out of the event bucket,
which is now known by the views as
the “ViewState” bucket.
<modelglue>
ModelGlue.XML
<event-handlers>
<event-handler name="user.login">
<views>
<include name="personalInfo"
template="dspPersonalInfo.cfm" />
<include name="body" template="dspLanding.cfm" />
</views>
…
</event-handler>
</event-handlers>
</modelglue>
Model-Glue: Unity
Commonly used MG functions to interact with
the Event Bucket (within a controller):
• GetValue([name of formfield])
• ValueExists([name of formfield])
• SetValue([variable name],[value])
• Trace([variable name],[value])
Outstanding, simple documentation at
http://docs.model-glue.com/
Model-Glue: Unity
Views!
• Live in the Views directory(see coldspring.xml,
modelglue bean definition)
• Contain all of your html and layout
• Get their dynamic data from the ViewState bucket
• Rendered in the order defined in Modelglue.xml
• Last template rendered is it!
• Rendered views are all placed on the “viewstack”
• Rendered views can be included within one another.
Model-Glue: Unity
Views!
• Retrieve all needed values out of the viewstate first thing
(neatness, readability)
<cfset lex = viewstate.getValue("lexicon") />
<cfset linkQuery = viewstate.getValue("linkQuery") />
• Retrieve all needed rendered views out of the ViewStack
<cfset NavView = viewcollection.getView("nav") />
• Use the values/views within your template!
<span class="contentTitle">
<cfoutput>#lex.getTerm("pod.reports.title")#</cfoutput>
</span>
<div id="nav">
<cfoutput>#NavView#</cfoutput>
</div>
Model-Glue: Unity
Commonly used MG functions to interact with
the Viewstate and ViewCollection (within a
display template):
• Viewstate.GetValue([name of value])
• Viewstate.Exists([name of value])
• ViewCollection.Exists([name of rendered
template, as defined in modelglue.xml event])
• ViewCollection.getView([name of view])
Outstanding, simple documentation at
http://docs.model-glue.com/
Model-Glue: Unity
Controllers!
• Live in the Controller directory
• Perform any needed communication with Model-Glue
• Methods will typically receive the Event bucket object as
an argument, and nothing more (see modelglue.xml for
exception)
• Role is to facilitate exchange of data between the model
and the view via the Event bucket…that’s it.
• KISS it when writing controller functions…should be
short and sweet, with all business logic/rules in the
model.
Model-Glue: Unity
Segregating Functionality: Rules of Thumb
Controller
•
•
•
•
The controller’s job is nothing more than facilitating the exchange of information between the view
and the model.
The role of the controller should always be minimized as much as possible.
No business logic or rules should ever be found in the controller
Sample controller function:
<cffunction name="makeOrgTree" access="public" output="false" returntype="void" hint="I'll return
you an org tree in whatever form you request it, for the currently selected org">
<cfargument name="event" type="any" required="yes"/>
<cfset var format = arguments.event.getArgument("format") />
<cfset var orgID = session.currentUserOrg.getOrganizationID() />
<cfset var ORM = getModelGlue().getORMService() />
<cfset var retTree = getOrganization().makeOrgTree(orgID,ORM,format) />
<cfset arguments.event.setValue("orgTree",retTree) />
<cfset arguments.event.trace("org tree result",replace(retTree,"""","\""","all")) />
</cffunction>
(where the ‘argument’ value came from in the actual event doing the broadcast…)
<message name="makeOrgTree" >
<argument name="format" value="STRING" />
</message>
Model-Glue: Unity
Segregating Functionality: Rules of Thumb
Generally Speaking…
• If coordination between two or more objects is required, you should
probably handle that by creating a service layer object in your model
• A View template must be self-sufficient…never talks to anyone but the
viewstate or viewcollection (no ‘session’, no ‘application’, no nothing else!)
• Consider using a “persistence façade” to handle communication with
session, client, or whatever ‘sticky’ scope you choose.
• When architecting/designing objects for the model, do so completely without
the framework in mind at all! They should be stand alone and self-sufficient.
• Consider using a configuration object to hold application configuration data,
such as DSN, security considerations, etc. Sample configuration object
bean definition with coldspring.xml:
<bean id="configuration" class="model.configuration">
<property name="forceLogin"><value>false</value></property>
<property name="publicEvents">
<value>page.about,page.faq,page.contact,page.login</value>
</property>
<property name="loginEvent"><value>home</value></property>
<property name="dsn"><value>cwes_prod</value></property>
</bean>
Model-Glue: Unity
Model-Glue Application
Architecture: How
my team does it
• Define basic functionality/data sets
• Perform “Ontology” for each area
• Write stubbed out CFCs (with CFCDocs in mind
to make it self-documenting)
• Assemble coded components
• Supplement with Canvas Wiki
Model-Glue: Unity
Model-Glue Application
Architecture: How
my team does it
Model-Glue: Unity
Model-Glue Application
Architecture: How
my team does it
ONTOLOGY
Ask the questions (for instance, regarding a lexicon object):
•What do I know about myself?
•I know what language is currently selected;
•I know the ID of the current user’s employer
•What can I do?
•I can retrieve a lexicon term based on incoming term key,
either a default value or the employer’s override value;
•I can create a new lexicon term
•I can edit an existing term
Model-Glue: Unity
Model-Glue Application
Architecture: How
my team does it
Stub out CFC(s)
Based on ontology exercise:
•Write a CFC that contains methods and variables to cover all
points
•Determine what other objects this CFC will be dependent upon
(if any) and inject them
•If coordination between objects is needed for this CFC, make it
a service layer object and move the real functionality down to
lower level objects
•Write methods to include only incoming arguments. Comment
heavily to explain what functionality will take place within that
method.
•ALWAYS populate ‘HINT’ attributes of all tags! This enhances
self-documentation and assists the programmer.
Model-Glue: Unity
Model-Glue Application
Architecture: How
my team does it
CODING
•Divvy work out to programmers!
•Assemble components as completed
•Utilize MG’s ability to use includes within
Modelglue.xml in order to alleviate work overwriting.
<modelglue>
<include template="/config/AdminEvents.xml" />
…
</modelglue>
Model-Glue: Unity
COLDSPRING!
What does it do?
•Manages your objects for you
•Instantiates/creates them;
•Automagically injects needed objects within other objects;
•Provides “one stop shopping” point at which to manage
configuration settings for objects
•Allows you to automagically inject functionality on a global scale
(logging, for instance)
•Probably several other things I’m not aware of
Model-Glue: Unity
COLDSPRING!
Two ways to put an object inside of another object:
•Without Coldspring:
<cfcomponent>
<cffunction name=“init” returntype=“any”>
<cfset variables.objActivityCenter =
createObject(“component”,”model.activitycenter”).init(url=http://www.fiservhe
alth.com/webservices.cfm?wsdl) />
</cffunction>
…
</cfcomponent>
(at this point, any method within the cfc can get at the
ActivityCenter object)
ActivityCenter object used in multiple other objects…interface
changes…what then?
Coldspring provides the answer.
Model-Glue: Unity
COLDSPRING!
Two ways to put an object inside of another object:
WITH Coldspring(step 1):
•Define the object inside of Coldspring.XML;
<bean id="activitycenter" class="model.activitycenter">
<property name="url">
<value>http://www.wausau.com/activitycenter.jsp?wsdl</
value>
</property>
</bean>
Notice that we are setting the value of the required ‘URL’ parameter
here, within the bean definition, so any object using ActivityCenter will
never have to pass it in…Coldspring does that for us when it creates the
Activitycenter bean!
Model-Glue: Unity
COLDSPRING!
Two ways to put an object inside of another object:
WITH Coldspring (step 2):
•Create obligatory getters and setters inside the components that need
another object injected.
<cfcomponent>
<CFFUNCTION access="public" name=“setActivityCenter" output="false"
returntype="void" HINT="I set the activitycenter obj to a local variable">
<CFARGUMENT name=“ActivityCenter" type="model.ActivityCenter"
required="true" />
<CFSET variables._ ActivityCenter = arguments. ActivityCenter />
</CFFUNCTION>
<CFFUNCTION access="public" name="getActivityCenter" output="false"
HINT="I retrieve the ActivityCenter obj from a local variable">
<CFRETURN variables._ ActivityCenter />
</CFFUNCTION>
</cfcomponent>
Coldspring sees the getter and setter, knows it has a bean named
ActivityCenter, and will automatically inject it for you! If the URL or other
ActivityCenter parameters EVER change, you need only change it once within
the Coldspring.XML file. SWEET!
EXTRAS
Selecting a Framework
Why?
• App needs to remain flexible and growth
oriented;
• High degree of customization potentially
needed;
How?
• Scope out a small but relevant app and build it
with each of the flavors being considered.
EXTRAS
OTHER LINKS:
CFCDoc
http://www.spike.org.uk/projects/cfcdoc/index.cfm
MGDoc
http://ray.camdenfamily.com/index.cfm/2006/3/30/MGDoc-a-ModelGlue-documentor
Canvas Wiki
http://ray.camdenfamily.com/index.cfm/Canvas-Wiki