|
Relational Object Programming, Four "Concerns"
Main Driver / Controller Object
Shared Workspace Object
Rule Object(s)
Task Object(s)
Main Driver / Controller Object
- Locate and sequence application objects, required and optional. All
of the pieces and parts of the application can be assembled after the
inbound datastream has been scanned for anomalies, specific values,
and in-stream directives. For auditing and regulatory purposes, only
the programs that are actually needed are loaded and then executed.
- Implement the global data vector between every object. Parent-child
relationships do not exist because Busines Rules and application features
are assembled based on need. Traditional software design mandates 100%
assembly of every program in the application for every session. RRP
design does not assume that every component, feature version, and business
rules will be present. The global datavector is a shared connection
from workspace to every object that IS present during a session.
- Execute objects in the specified sequence. The controller does not
evaluate which objects are to be executed. The optimal solution is to
move evaluation logic into a Rule or Task object. RRP models maintain
an absence of conditional execution logic in the controller.
Shared Workspace Object
A simple application may use a single datavector that contains all
of the NUM and CHAR values from a single observation to be shared across
datasets and procedures. This is the easy way to simplify complex Macros.
A global datavector is the location for arrays and RDBMS observations
aggregated from any number of local and/or remote sources. Shared data
is automatically piped into every object that is coded to designate
a specific need for shared data. When data is accessible on a global
basis, there is no need to pass parameters between programs.
Rule Object(s)
Evaluates data in Shared Workspace or in a SAS dataset. This component
can set/reset a flag in Shared Workspace, modify rows or columns in
the dataset, or enable/disable a specific software component.
Task Object(s)
Every remaining sofware feature, functionality, etc.
COMMUNICATIONS, INDEPENDENCE
Repository Relationship Programming (RRP) defines an intermediate
relationship between each object. The idea is to physically separate
objects from each, using a logical connection instead.
Communications Independence
Prohibit most implementations of dot-notation where the parent object
invokes a child object..
objectName.methodName();
Prohibit the use of events with parameters.
_sendEvent('event name', arg1, arg2, arg3);
Prohibit the use of parameters between programs.
objectName.methodName(arg1, arg2, arg3);
Prohibit most implementations where the parent object makes a direct
exchange of data with a child object.
varName=objectName.varName;
objectName.varName=varName
Physical Independence
Remove IMPORT, _NEW_, and INCLUDE statements.
Remove hardcoded program names, operating system paths, and macro
parameters.
"..flexibility over the long haul, with attendant reduction
of cost and containment of technical risk, requires more than the mere
*form* of modularity -- and it also requires a match between responsibility
and control. It's easy to do something once, or even to do it for a
while, but that it's much harder to establish a process that does that
same thing reliably for weeks or months or years at a time."
Peter Coffee, Ziff Davis
OBJECT INDEPENDENCE
Create a list of every object (a.k.a. SAS program) that is used in
the application. Create a dataset listing of SAS objects by reading
the specified SAS Catalogs with Proc SQL.
- This dataset contains 50% of the information necessary to create
automatic flowcharts.
The following object source code demonstrates how to assemble a SAS
application without IMPORT or INCLUDE statements
class standardIncludeTemplate; public list application / (sendEvent='N'); runInterface: method; dcl num dset; dcl char arg1 arg2 arg3 arg4; dcl object thisProgram; submit continue; proc sql; create table work.objects as select * from sashelp.vcatalg where libname='MONTURA' and memname='R4_LINKLIST' and objtype='CLASS'; quit; endsubmit; dset=open('work.objects', 'i'); do while (fetch(dset)=0); arg1=getvarc(dset, varnum(dset, 'libname')); arg2=getvarc(dset, varnum(dset, 'memname')); arg3=getvarc(dset, varnum(dset, 'objname')); arg4=getvarc(dset, varnum(dset, 'objtype')); thisProgram=instance(loadclass(arg1||'.'||arg2||'.'||arg3||'.'||arg4)); inserto(application, thisProgram, -1); end; close(dset); endmethod; endclass;
THE RELATIONSHIP CONDUCTOR
Applications are composed of a variable number of objects, per session.
Two objects that currently execute in sequence can be separated with
one (or more) new rule objects at the click of a mouse. The solution
is to implement something that can make data available to every object,
regardless of execution sequence.
With this approach, there is no need to pass positional and keyword
parameters between programs. The SCL list is the perfect conductor
because it can be loaded with numeric and character data elements at
the same time.
Most applications need the following types of data channels.
- Primary data channel(s) for single-iteration data
- Secondary channel(s) for session data.
- A primary channel for messages that control session go/stop status.
- Secondary channel(s) for messages related to business-rules and
other toggles
class universalDataVector; public list sku / (sendEvent='N', description='Data channel');
public list storeCount / (sendEvent='N', description='Data channel);
public list messages / (sendEvent='N', description='Execution control channel');
public list rules / (sendEvent='N', description='Business rule toggles'); endclass;
COMMUNICATION CHANNELS
The implementation of Karl Weick's intermediate relationship
is the list attribute named sku. It works just like a local attribute
(variable) within the current object. This example shows how to read
one row from a SAS dataset and insert every variable, character and
numeric, into a single global vector.
Each data element is named with the column name in the SAS dataset.
class item; public list sku / (sendEvent='N'); public list activeMethods / (sendEvent='N');
public list messages / (sendEvent='N'); runInterface: method; dcl num xMethod;
do xMethod=1 to listlen(activeMethods) while (listlen(messages)=0); call send(_self_, getitemc(activeMethods, xMethod)); end; endmethod; interface1: method; submit continue; proc SQL undo_policy=none inobs=1; create table work.temp as select *
from sysdata.inventory where sku_status=0; quit; endsubmit; endmethod; interface2: method; dcl num dset i; dset=open('work.temp', 'i'); fetch(dset); do i=1 to attrn(dset, 'NVARS'); if vartype(dset, i)='N' then insertn(sku, getvarn(dset, i), -1, varname(dset, i)); else insertc(sku, getvarc(dset, i), -1, varname(dset, i)); end; close(dset); endmethod; endclass;
The next object to execute simply reads data populated by the ITEMS
object from the SKU attribute. The following source code shows how to
fetech a single data element from the global data vector.
class storeplanning; public list sku / (sendEvent='N'); public list storeCount / (sendEvent='N'); public list activeMethods / (sendEvent='N'); runInterface: method;
dcl num xMethod;
do xMethod=1 to listlen(activeMethods) while (listlen(messages)=0); call send(_self_, getitemc(activeMethods, xMethod)); end; endmethod; interface1: method; dcl char this_sku=getnitemc(sku, 'sku_id'); submit continue; proc SQL undo_policy=none; create table work.temp as select count(distinct store_id) as count, alpha_id from sysdata.storeplanning where sku_id='&this_sku' group by alpha_id; quit ; endsubmit; endmethod; interface2: method / (description='Store Count by Geo-Alpha'); dcl char arg1; dcl num dset arg2; dset=open('work.temp'); do while (fetch(dset)=0); arg1=getvarc(dset, varnum(dset, 'alpha_id')); arg2=getvarn(dset, varnum(dset, 'count')); insertn(storeCount, arg2, -1, arg1); end; close(dset); endmethod; endclass;
THE CONNECTION
A system utility automatically links universalDataVector to every
object in the application.
Data is omnipresent within the session.
Read the technical specification for complete details: Repository
Relationship Programming.
|