RAD OOWeb Maniacs 2008
Peter BellSystemsForge
Who Am I?Programmer - 30-40 projects/yr.Researcher - Published academic papers DSM forum/ooPSLAEntrepreneur - Profitable/practicalSystemsForge - 10,000 custom apps/yr.Writer - CFDJ, Fusion Authority QuarterlyPresenter - cf.objective(), CF United, Frameworks, Code Generation 2007, ooPSLA, Domain Specific Modeling Forum, CFCamp . . .
RAD OO . . . Patterns - quickly build OO apps Proven (> 50 projects) Collection of tools
RAD OO . . . IS NOT . . .
Standard approach Suitable for all projects Hack job
IS . . . Fast DRY Maintainable
RAD OO Uses XML Config Base Classes Optional Classes Iterating Business Objects RAD Controller Smart Views RAD Views Custom Data Types
XML Config<?xml version="1.0" encoding="UTF-8"?><controller>
<title>ProductCatalog</title><name>ProductCatalog</name><defaultAction>viewCategory</defaultAction><actions>
<detail name="viewCategory" object="ProductCategory" method="getByID" PropertyValueList="%Input.CID%" screen="product-catalog-category-detail" />
<detail name="viewProduct" object="Product" method="getByID" PropertyValueList="%Input.PID%" screen="product-catalog-product-detail" />
<display name="displaySearchResults" Data="" screen="product-catalog-search-results" />
</actions></controller>
XML ConfigProduct extends: BaseObject tableName: tbl_ProductIdentity: ProductID
Properties: Title title required Price money optional default:0 Description WYSIWYG optional
ClassMethods: AdminList: Title,Price OrderBy Title DefaultAdd: Title,Price,Description QuickAdd: Title,Price multiple:5 DefaultEdit: ID, Title,Price,Description
Relationship has-many Category associated optional
Base Classes
Most code similar Replace code with configuration Samples: BaseService, BaseDAO,
BaseController
Optional Classes
Only create CFC’s with code All others instantiate base classes
Lightwire ConfigBusinessObjectList = ApplicationConfig.get("ObjectList");For (i = 1; i lte listlen(BusinessObjectList); i = i + 1) {
// Get current object nameBusinessObjectName = ListGetAt(BusinessObjectList, i);
// Configure Business Object Service ClassesIf (FileExistsinApplication("com.model.#BusinessObjectName#Service")){addSingleton("lb.com.model.#BusinessObjectName#Service");}Else{
If (FileExistsinLibrary("com.model.#BusinessObjectName#Service"))
{addSingleton("lightbase3.library.com.model.#BusinessObjectName#Service");}Else{addSingleton("lightbase3.framework.com.base.BaseService",
"#BusinessObjectName#Service");};};
addConstructorDependency("#BusinessObjectName#Service","#BusinessObjectName#Metadata", "Metadata");
addMixinDependency("#BusinessObjectName#Service","#BusinessObjectName#DAO");addMixinDependency("#BusinessObjectName#Service","DBProvisioner");
};
Iterating Business Object Encapsulates recordset Handles iteration Generic get/set - can overload Pattern - not implementation E.g. Can drop generic get/set
Traditional view (initial)<cfoutput query="ProductList">
#ProductID#<br />#Title#<br />#Image#<br />#SKU#<br />#Price#<br />#SalePrice#<br /><br />
</cfoutput>
Traditional view (after time)<strong>#Title#</strong><br /><cfif len(image)><img src="/ibo/sample/images/#Image#" width="80"><br /><cfelse><img src="/ibo/sample/images/no-image.gif" width="80"><br /></cfif><cfif Len(SKU)>#SKU#<br /></cfif><cfif SalePrice><strong>On sale - only $#Numberformat(SalePrice, "9.99")#<br /></strong><cfelse>Price: $#Numberformat(Price, "9.99")#<br /></cfif>
Traditional view (not DRY)
Product list (multiple?) Product detail (multiple?) Admin product list Cart display Order display . . . .
IBO (initial)<cfloop condition="#ProductList.next()#">
#ProductList.display("ProductID")#<br />#ProductList.display("Title")#<br />#ProductList.display("Image")#<br />#ProductList.display("SKU")#<br />#ProductList.display("Price")#<br />#ProductList.display("SalePrice")#<br /<br />
</cfloop>
<cfloop condition="#ProductList.next()#">#ProductList.displayProductID()#<br />#ProductList.displayTitle()#<br />. . .
</cfloop>
OR
IBO (over time)
<cfloop condition="#ProductList.next()#">#ProductList.displayProductID()#<br />#ProductList.displayTitle()#<br />. . .
</cfloop>
OR
<cfloop condition="#ProductList.next()#">#ProductList.display("ProductID")#<br />#ProductList.display("Title")#<br />#ProductList.display("Image")#<br />#ProductList.display("SKU")#<br />#ProductList.display("Price")#<br />#ProductList.display("SalePrice")#<br /<br />
</cfloop>
The Concept
Using the IBOCREATE:<cfscript>
var ProductList = beanFactory.getbean("Product");ProductList.load(GetProducts);
</cfscript>
ITERATE:<cfset ProductList.reset()><cfloop condition="#ProductList.next()#">
#ProductList.get("Title")#<br /></cfloop>
PERFORMANCE:- Single bean - quick to create
M-V-C
Model: Business logic and persistance
View: Display templates and helpers
Controller: Actions, model calls, selects views
RAD Controller
Front controller index.cfm?action=<controller>.<method>
Page controller about-us/history.html becomes page.cfm?filepath=about-us/history
Remote controller remote.cfm?object=<object>&
method=<method>&p1=v1&p2=v2& . . .
Smart Views
View can access model Not true MVC DRYer - for right use cases
Smart Views Regular Controller:
Data = getProductList() View = product-list.cfm
Smart View: <cfset ProductList = ProductService.getProductList()>
Great for: Ancillary data one off screens
RAD Model For each business object:
Service a) remote apib) aggregate methodsc) factory
DAO a) All data access (uses data mapper)
Business object Business logic
RAD View
Site Templates Screen Templates Includes View Helpers (IBOs) Custom Data Types
Site Templates
Complete HTML page 1..n/project Template chooser
Screen Templates
Populates content area May have includes/helpers
View Helpers
CFC methods for simplifying templates
E.g. list paging
Custom Data Types
Displaying form fields Processing form fields Displaying formatted values
Custom Data Types
.display() .field() .process()
Conclusions
Proven in over 50 projects Extremely productive Removes unnecessary flexibility Your milage may vary