Instant Flowchart
Instant Flowcharts are exclusive to Repository Relationship Programming.
- Step-oriented error detect logic is a big advantage during software
development. Even the bare-bones basic information is enough to show
exactly where the error/problem occurred.
- Error detect logic is tied together, application wide. This becomes
indispensable when debugging in production. Error-detect logic pinpoints
the error stops the application immediately, without generating the
cascade of errors like Base/SAS.
- Detailed flowchart information can be stored in a dataset and compared
against production results. Both information streams can be compared
with PROC COMPARE, providing instant feedback on system status and
expected response.
- Content may vary from session to session, showing every program
in the application run. The scope of information can customized to
cover the entire application, a single feature, or a single subroutine.
After loading the application into memory, a standard routine pulls
identity information from each instance. A bare-minimum implementation
would show the 4-level name and execution sequence of each SAS object
that is used in the application. .The physical location of the SAS catalog,
a detailed description of the application purpose, usage notes, and
a description for each component can also be presented.
RRP applications are designed so that some flowchart information can
be stored in SAS catalogs. Information stored in a SAS catalog can be
extracted with SQL. Machine readable SDLC documentation is invaluable
when SAS programs are maintained by a series of programmers over a period
of time.
Displayed in the SAS Log.
EPA Groundwater Compliance Flowchart
Path: c:\commenvct\padwis
Catalog: GWCOMPLIANCE
The following programs execute in the following sequence.
Required Programs: 29
Optional Programs: 0
Sequence: 01 / 100, Program: COMPGUI.GWCOMPLIANCE.DATES.CLASS
Sequence: 02 / 200, Program: COMPGUI.GWPOPULATION.FOURLOG.CLASS
Sequence: 03 / 200, Program: COMPGUI.GWPOPULATION.TRMTPROC.CLASS
Sequence: 04 / 201, Program: COMPGUI.GWPOPULATION.EPTP.CLASS
Sequence: 05 / 201, Program: COMPGUI.GWPOPULATION.SOURCETP.CLASS
Sequence: 06 / 202, Program: COMPGUI.GWPOPULATION.UNTREATEDGROUND.CLASS
Sequence: 07 / 300, Program: COMPGUI.GWPOPULATION.POPULATION4LOG.CLASS
Sequence: 08 / 301, Program: COMPGUI.GWPOPULATION.RTM.CLASS
Sequence: 09 / 302, Program: COMPGUI.GWPOPULATION.RTMFOURLOGCOMPUTED.CLASS
Sequence: 10 / 400, Program: COMPGUI.GWCOMPLIANCE.RTMSEASON.CLASS
Sequence: 11 / 401, Program: COMPGUI.GWCOMPLIANCE.RTMSAMPLE.CLASS
Sequence: 12 / 450, Program: COMPGUI.GWCOMPLIANCE.CALENDAR4LOGDAYS.CLASS
Sequence: 13 / 450, Program: COMPGUI.GWCOMPLIANCE.CALENDARCONTAMWINDOW.CLASS
Sequence: 14 / 450, Program: COMPGUI.GWCOMPLIANCE.CALENDAREPWINDOW.CLASS
Sequence: 15 / 450, Program: COMPGUI.GWCOMPLIANCE.CALENDAROFFSEASONDAYS.CLASS
Sequence: 16 / 475, Program: COMPGUI.GWCOMPLIANCE.CALENDARSHUTDOWNABSENT.CLASS
Sequence: 17 / 500, Program: COMPGUI.GWCOMPLIANCE.CALENDARREQUIREDDAYS.CLASS
Sequence: 18 / 550, Program: COMPGUI.GWCOMPLIANCE.SAMPLEACTIVE.CLASS
Sequence: 19 / 700, Program: COMPGUI.GWCOMPLIANCE.SAMPLEABSENTDETECT.CLASS
Sequence: 20 / 701, Program: COMPGUI.GWCOMPLIANCE.SAMPLEABSENTSUMMARY.CLASS
Sequence: 21 / 702, Program: COMPGUI.GWCOMPLIANCE.VIOLATIONSAMPLEABSENT.CLASS
Sequence: 22 / 725, Program: COMPGUI.GWCOMPLIANCE.CALENDARREQUIREDXTRA.CLASS
Sequence: 23 / 750, Program: COMPGUI.GWCOMPLIANCE.BELOWLIMITDETECT.CLASS
Sequence: 24 / 751, Program: COMPGUI.GWCOMPLIANCE.BELOWLIMITMATRIX.CLASS
Sequence: 25 / 752, Program: COMPGUI.GWCOMPLIANCE.BELOWLIMITROLLUP.CLASS
Sequence: 26 / 753, Program: COMPGUI.GWCOMPLIANCE.VIOLATIONTIMELIMIT.CLASS
Sequence: 27 / 800, Program: COMPGUI.GWCOMPLIANCE.VIFC.CLASS
Sequence: 28 / 900, Program: COMPGUI.GWCOMPLIANCE.VIFCSTATUSLOW.CLASS
Sequence: 29 / 901, Program: COMPGUI.GWCOMPLIANCE.VIFCSTATUSABSENT.CLASS
FIGURE #1
With additional information, for the programmer can answer why each
program completed successfully, failed, or was skipped over without
executing. Objects provide a structure where SAS programmers can select
a point in the process where it makes sense to save data vector information,
flag settings, and parameters values to a SAS dataset for auditing.
Repository Relationship
A repository is a SAS catalog that contains SAS objects that fulfill
a specific purpose, function, or logical step.
Repository content is determined based on how the application must
execute after the instances are in memory and ready to execute. Every
object in the repository is instantiated and loaded into memory as a
collective. In contrast, old programming design treats a repository
as a library where each object must be individually selected or referenced
by physical name to included.
A collective is designed as a series of physically independent instances
(programs). Each collective may be replicated any number of times for
parallel processing / multiple scenario response.
Each instance is related to others in the same repository in many different
ways that include:
- Sequence of position in the execution cue (the most common).
- A singleton that can be invoked by name, but only after instantiation
(perfect for functions with version identifiers).
Each repository of instances relates to the application through the
Data Relationship to obtain the following:
- Data - SAS dataset, Oracle table, etc.
- Parameters set by any other instance, anywhere in the application.
- Flag values set by any other instance, anywhere in the application.
- External metadata values.
Features that are unique to Repository Relationship Programming:
Each repository of instances and be repetitively included for parallel
threads within the same application - the application does not need
to be specifically designed for parallel threads.
Each repository of instances can be selectively removed, without
crashing the application.
SAS Object Application Example - one application, four repository.
- Groundwater - contains the main driver.
- groundwater100 - determine sample frequency for each public water
system.
- groundwater200 - examine data to determine when a water system operator
fails to sample for a specified contaminant.
- groundwater300 - issue one violation per failure unless the operator
was issued a waiver.

Figure #2
Repository Object Instantiation
The term "object" means a SAS source code that has been coded
and compiled, resulting in the creation of second file of the same name
with a suffix of ".class".
The term "instance" means that a SAS object has been loaded
into memory and turned into an executable. The object itself is NOT
executable. Additional CPU and operating bytecode must be inserted during
instantiation process or the instruction set within the object will
be meaningless to the CPU and operating system.
Relational objects are physically independent before instantiation.
For beginners, the fast and easy way to get started is use a class-level
property with a hardcoded number that signals each position in a serial
relationship. In the example below, the programmer has objects stored
in two SAS catalogs. A class level property named RUNSEQUENCE is hardcoded
with the sequence each should execute. See Figure #1 above to see the
numerical order of each program side-by-side with the sequence number
coded by the programmer.
Order of Operations
- PROC SQL creates a list of every SAS object in two SAS catalogs.
- INSTANCE turns each object into an executable instance.
- INSERTO stores the instance identifier.
- SORTLIST sorts every instance identifier in the application to get
correct execution sequence, based on the RUNSEQUENCE property.
public list component / (sendEvent='N');
runInterface: method; dcl num dset; dcl char name1 name2 name3 name4; dcl object thisProgram; submit continue sql; create table work.temp as select * from sashelp.vcatalg where libname='EPA' and memname in('GWCOMPLIANCE','GWPOPULATION') and objtype='CLASS'; quit; endsubmit; dset=open('work.temp', 'i'); do while (fetch(dset)=0); name1=getvarc(dset, varnum(dset, 'libname')); name2=getvarc(dset, varnum(dset, 'memname')); name3=getvarc(dset, varnum(dset, 'objname')); name4=getvarc(dset, varnum(dset, 'objtype')); thisProgram=instance(loadclass(name1||'.'||name2||'.'||name3||'.'||name4)); inserto(component, thisProgram, -1, put(thisProgram.runSequence, z4.)); end; close(dset);
delete('work.temp'); sortlist(component, 'name'); endmethod;
FIGURE #2
Repository Instance Execution
This execution stage is traditionally the most complex
portion of the programming effort. Some parts of the application become
so complex with minutia that some code is impossible to understand without
data flow diagrams, flowcharts, and language debuggers. A bad situation
is made even worse with bad programming technique: spaghetti code, GOTO
statements, and blocks of code that are no longer used but remain because
no one remembers why it was coded in the first place.
"If the devil is in the details, clean code keeps the devil
under control."
Step #1: Remove any Potential for Main Driver Mess
Limit the main driver to a single purpose. - execute each
instance, one after another, in sequence. Any decision to execute on
a conditional basis does not belong in this block of logic. There only
possible error that can occur in the main driver, it occurs when the
programmer fails to create a method named runInterface in one of the
repository programs.
The Repository Relationship Programming specification
uses the name runInterface as the naming for convention for "main
driver" logic in every object, including SAS/Frame widgets.
public list component / (sendEvent='N');
public list gMessage / (sendEvent='N');
runInterface: method; dcl num xObject; dcl object thisObject; do xObject=1 to listlen(component) while (listlen(gMessage)=0); thisObject=getitemo(component, xObject); thisObject.runInterface(); end; endmethod;
Step #2: Identify Error Location
Use one or more global channels (i.e. gMessage) to evaluate
"if" the application should terminate in response to errors,
missing data, or unexpected data combination that is detected in any
repository instance. Think of this as the power to know every possible
error location, in terms of repository, program, and method.
- The automatic variable DESCRIPTION is the four-level qualifier of
the SAS object.
- The automatic variable _METHOD_ is the name of the method.
Two data elements pinpoint the exact error location, regardless of
how many lines of code are used in the SAS application.
interface1: method / (description='Samples for EP that must MUST monitor for contaminents'); submit continue sql; create table activeIndex as select a.compkey, a.epkey, a.logdemo, a.windowdate format=mmddyy10., b.sampdate format=mmddyy10., b.samptype, b.sampid from calendarContamWindow a left join sampleSystem b on a.compkey=b.sfkey and a.windowdate=b.sampdate where a.compkey in(select distinct compkey from rtmFourlogSystem) order by compkey, windowdate, samptype; quit; endsubmit; if symgetn('sqlrc') then insertc(gMessage, description||' '||_method_, -1); endmethod;
The following code is common to all SAS objects.
The error message created by INTERFACE1 feeds the global message channel
in the "local" main driver of the repository instance. If
an error is detected in INTERFACE1 then CALENDARSHUTDOWNABSENT stops
execution immediately, regardless of how many steps remain. Because
gMesssage is also connected to the application-level main driver, the
entire application stops immediately - without "crashing"
or "bombing".
class calendarshutdownabsent; public num runSequence / (initialValue=475); public list gMessage / (sendEvent='N', autocreate='N'); public list interface / (initialValue={ 'interface1', 'interface2', 'interface3', 'interface4', 'interface5', 'interface6', 'interface7', 'interface8', 'interface9' }); _init: method / (state='o'); _super(); gMessage =getniteml(envlist('G'), 'message'); endmethod; runInterface: method; dcl num xMethod; do xMethod=1 to listlen(interface) while (listlen(gMessage)=0); call send(_self_, getitemc(interface, xMethod)); end; endmethod;
Deprecated Coding Practices
- Method parameters
- Named and positional parameters
- Passing macro variables between instances
- Parent-child hierarchy between instances
Relationship: Limitations & Exclusions
- Any number of instances may participate in a relationship.
- Instances may join, and subsequently leave, a relationship at
any time.
- A relationship may be implemented across any number of physically
separate software applications
|