Wie sollen SAS-Programme in Dateien, Makros und Abschnitte aufgeteilt werden? Es ist zwar mehr Arbeit, Programme in einzelne Makros aufzuteilen, aber es fördert die Wartbarkeit und die Wiederverwendbarkeit und vereinfacht Tests und Versionskontrolle. Eine wichtige Frage dabei ist, wann man aufteilt und wann lieber nicht, weil es dadurch auch komplizierter wird.
Wenn man Makros verwendet, stellt sich die Frage, wie man Parameter übergibt - nach Position oder in der Form name=wert - und wie man aus dem Makro Werte zurückgibt.
Der Titel dieses Beitrags ist möglicherweise ein bißchen gewagt, das Konzept, das ich hier zur Diskussion stellen will, aber nicht minder :-)
Kurz gesagt: Mir scheint es häufig sinnvoll, verschiedene Verarbeitungsschritte einer komplexeren Verarbeitung in einem Makro zusammenzufassen - insbesondere dann, wenn die einzelnen Schritte viele Abhängigkeiten untereinander aufweisen. Die Zusammenfassung in einem Makro macht aus meiner Sicht dann deshalb Sinn, weil man bei Änderung in einem Schritt die anderen Schritte mit hoher Wahrscheinlichkeit auch ändern muß. Man hat die von einer Änderung betroffenen Stellen einfach gleich vor Augen.
Was dabei rauskommt, sind dann Makros, die - objektorientiert gesprochen - verschiedene Methoden (die Verarbeitungsschritte) implementieren.
Ein Beispiel: Der SAS-Log-Parser, den ich hier im Projekt Yalan eingestellt habe, wird durch das folgende Makro gestartet:
%macro rdsStartYalan;
%* Reset configuration;
%rdsYalan (resetLogFiles);
%* Where to look for new log files;
%rdsYalan (addLogFiles, c:\saslogs, *.log);
%rdsYalan (addLogFiles, c:\saslogs, *.saslog);
%* In which time intervall to look for new log files;
%rdsYalan (setPollingInterval, 15);
%* Set the library (e.g. "c:/MyLDB") to write the log database to and (optionally)
name the share server to access the log database (e.g. "sassrvt1");
%rdsYalan (setLDBLibrary, c:\sasldb, sassrvt1);
%* Yalan will execute the statements contained in the following file every time
it polls for new log files. You may stop the Yalan Daemon by passing the
following statement via this file: %rdsYalan (stopDaemon);
%rdsYalan (setCommandFile, c:\sasldb\yalanCmds.sas);
%* Start the Yalan daemon;
%rdsYalan (startDaemon);
%mend;
Das in diesem Ablauf mehrfach aufgerufene Makro rdsYalan ist dann - etwas gekürzt:
%macro rdsYalan (method, value1, value2);
%global
RDSYALAN_LogFileNameCount
RDSYALAN_LDBLibname
RDSYALAN_LDBLibrary
RDSYALAN_PollingInterval
RDSYALAN_CommandFile
;
/* Hier hab' ich gekuerzt :-) */
/**
* Method: addLogFiles
*/
%if (%lowcase (&method.) = %lowcase (addLogFiles)) %then %do;
%local _exists _i;
%let _exists = 0;
%do _i=1 %to &RDSYALAN_LogFileNameCount.;
%if ( "&&RDSYALAN_LFD&_i." = "&value1."
and "&&RDSYALAN_LFP&_i." = "&value2."
) %then
%let _exists = 1;
%end;
%if (&_exists. = 0) %then %do;
%let RDSYALAN_LogFileNameCount = %eval(&RDSYALAN_LogFileNameCount. + 1);
%* Declare new global variable "rdsYalanLFN<n>", "rdsYalanLDN<n>";
%global RDSYALAN_LFD&RDSYALAN_LogFileNameCount.;
%global RDSYALAN_LFP&RDSYALAN_LogFileNameCount.;
%let RDSYALAN_LFD&RDSYALAN_LogFileNameCount. = &value1.;
%let RDSYALAN_LFP&RDSYALAN_LogFileNameCount. = &value2.;
%end;
%end;
/**
* Method: resetLogFiles
*/
%if (%lowcase (&method.) = %lowcase (resetLogFiles)) %then %do;
data _null_;
do _i=1 to &RDSYALAN_LogFileNameCount.;
call symdel ('RDSYALAN_LFD'!!left(put(_i,best.)));
call symdel ('RDSYALAN_LFP'!!left(put(_i,best.)));
end;
run;
%let RDSYALAN_LogFileNameCount = 0;
%end;
/**
* Method: startDaemon
*/
%if (%lowcase (&method.) = %lowcase (startDaemon)) %then %do;
%rdsLogFilePoller(start);
%end;
/**
* Method: stopDaemon
*/
%if (%lowcase (&method.) = %lowcase (stopDaemon)) %then %do;
%rdsLogFilePoller(stop);
%end;
%mend;
Wie gesagt: Aus meiner Sicht hat diese Strukturierung von Makro-Bibliotheken einige Vorteile. Ich will allerdings nicht ausschließen, dass dieses Konzept nur daraus resultiert, dass ich täglich mehrfache zwischen der SAS- und der Java-Welt wechsle, und dass der Versuch OO-Strukturen auf SAS-Makros zu übertragen jedem, der das nicht tut, restlos kurios erscheint.
M.a.W.: Feedback !
Gruß Stephan