Auf der 10. KSFE in Hamburg ist die Idee entstanden, gemeinsam auf Redscope SAS-Programmierrichtlinien zu entwickeln. Jeder kann an diesem Projekt mitarbeiten. Man kann als Redscope-Mitglied also neue Seiten in das Projekt einfügen oder einfach vorhandene Seiten kommentieren. Jeder kann die Seiten, die er selbst erstellt hat, beliebig oft überarbeiten, sobald sie freigeschaltet sind.
Programmierrichtlinien fördern die Lesbarkeit, Verständlichkeit und die Wartbarkeit von Programmen. Dies wird erreicht durch Regeln für die Strukturierung und die Vereinheitlichung und durch Tipps zur Fehlervermeidung.
Da ein großer Teil des Software-Lebenszyklus auf Wartung entfällt und da es erfahrungsgemäß oft vorkommt, dass ein SAS-Programmierer die Programme eines Kollegen ändern oder weiterentwickeln muss, sind Programmierrichtlinien für die effiziente Softwareentwicklung im Team unerlässlich.
Für manche Programmiersprachen, wie zum Beispiel Java, gibt es allgemein akzeptierte Programmierrichtlinien. Für SAS ist das bisher nicht der Fall.
In diesem Redscope-Projekt können wir gemeinsam SAS-Programmierrichtlinien entwickeln, siehe Anleitung.
Diese Programmierrichtlinien beziehen sich zunächst auf die SAS/BASE- und Makro-Sprache und nicht auf die SAS Component Language (SCL) oder auf die Interaktive Matrixsprache (IML).
Folgende Themen sollten aus meiner Sicht behandelt werden, diese Liste ist offen und die Inhalte werden sich entwickeln, ich möchte nur einen Anfang machen. Viele Themen werden strittig bleiben. Es wäre aber wünschenswert, wenn sich zumindest ein Kern von Regeln finden ließe, der als Ausgangpunkt für firmenspezifische Richtlinien verwendet werden kann. Metaregeln für die Anwendbarkeit (z.B. wann kann es sinnvoll sein, von den Regeln abzuweichen) können helfen, die Richtlinien im Alltag brauchbarer zu machen.
Als Startpunkt habe ich einige Links gefunden.
Verwandte Themen sind sicher Testen und Dokumentation von Programmen, Fehlerbehandlung und Änderungsverwaltung. Ich schlage vor, diese komplexeren Themen zunächst außen vor zu lassen.
Die Programmierrichtlinien sind in Kapitel gegliedert, jedes Kapitel kann beliebig viele Regeln enthalten. Das sieht dann zum Beispiel so aus:
SAS-Programmierrichtlinien
Anleitung
Codelayout
Regel 1 zum Codelayout: z.B. Einrückungen
Regel 2 zum Codelayout: z.B. Eine Anweisung pro Zeile
...
Modularisierung
Regel 1 zur Modularisierung
...
Kommentare
...
Namenskonventionen
Kontrollfluss
Fehlervermeidung
sonstiges
Metaregeln
Links
Diese Kapitel wurden bereits von mir angelegt.
Jedes Redscope-Mitglied kann nun:
Es ist sicher sinnvoll, wenn jede Regel knapp und präzise formuliert wird. Eine Begründung und eines oder mehrere Beispiele ergänzen die Regel. Manchmal ist es auch sinnvoll, ein Beispiel dafür zu geben, wie man es nicht machen sollte.
Die Überschrift einer Regel sollte treffend und maximal wenige Worte lang sein, weil dies die Navigation vereinfacht.
Links zu anderen Webseiten zu diesem Thema:
SAS® Programming Guidelines, ein Paper von der 31. SUGI
SAS® Programming Conventions, ein Paper von der 28. SUGI
Programmierrichtlinien - unterstützende Hilfe oder lästige Formalität?
Vortrag von Herrn Stefan Beimel auf der 10. KSFE, und das zugehörige Abstract.
Programmierrichtlinien, Folien 20-25 aus dem Tutorium "Validierung von SAS-Programmen" auf der 10. KSFE
Programmierstil bei Wikipedia
Einrückungsstil bei Wikipedia
Beim Codelayout geht es um die Verwendung von Einrückungen und Leerzeilen, das Platzieren von Anweisungen, Groß- und Kleinschreibung, und so weiter. Wie soll ein SAS-Programm gestaltet werden, damit es möglichst gut lesbar und auf einen Blick verstehbar wird?
Ein SAS-Programm ist schnell geschrieben, wenn aber mehrere Anweisungen in einer Zeile stehen oder wenn alle Anweisungen in Spalte 1 beginnen und wenn keine Leerzeilen verwendet werden, kann man es schlecht verstehen und weiterentwickeln.
Anleitung, wie jedes Redscope-Mitglied die Programmierrichtlinien bearbeiten kann.
Im Abschnitt "Links" unter dem Wikipedia-Link "Einrückungsstil" findet man den "Allman-Stil". Dieser Stil passt m.E. sehr gut zu SAS-Base und er wird bei uns (Schäfer Shop) "im Prinzip" verwendet.
Er hat zwar einen hohen Zeilenverbrauch, durch die Verwendung von 21"-Schirmen (zusammen mit normaler Schriftgröße) wird das mehr als wettgemacht. Man sieht dann 55 Zeilen Code (netto) je Bildschirm-Seite, da kann man einen "hohen" Zeilenverbrauch tolerieren.
Der große Vorteil vom "Allman-Stil" ist, dass man wunderbar mit copy&paste arbeiten kann. Jeder neuzeitliche Einrückungsstil sollte das copy&paste nicht behindern sondern erleichtern! Also lieber viele Zeilen und dafür leichter kopierbar (ich schreibe kaum ein if-then-else "frisch", ich kopiere fast immer von "obendrüber" oder von ähnlichen Stellen).
Die Steinzeitstile (z.B. 1TBS, 1TBS steht für "One True Brace Style", was übersetzt soviel bedeutet wie "einzig wahrer Klammern-Stil", siehe Wikipedia-Link) stammen aus der Zeit vor copy&paste und vor den 21"-Schirmen. Die C-Erfinder Kernighan/Ritchie hatten damals "dumme Terminals" mit 24 Zeilen je 80 Zeichen, darum kann man heute deren Zeilen-Spar-Stil getrost zu den Akten legen.
Wichtig ist uns:
Angepasstes Beispiel (Vorlage aus Wikipedia, Allmann-Stil):
Gruß Hans Kneilmann, Schäfer-Shop
Jeder DATA-Schritt wird mit einer RUN-Anweisung abgeschlossen. Jeder PROC-Schritt wird mit einer RUN-Anweisung abgeschlossen oder mit einer QUIT-Anweisung, falls dies die betreffende Prozedur erfordert.
Begründung: Dadurch wird vermieden, dass globale Anweisungen dem falschen Schritt zugeordnet werden und der Code wird leichter lesbar, da die Schrittgrenzen deutlich werden.
Beispiel für DATA-Schritt
Beispiel für PROC-Schritt
Beispiel für PROC-Schritt mit QUIT
so nicht: fehlendes RUN
Globale Anweisungen stehen nicht innerhalb eines Schritts, d.h. nicht zwischen der DATA- und der RUN-Anweisung und nicht zwischen der PROC- und der RUN- bzw. QUIT-Anweisung (siehe Schritte abschließen).
Begründung: Globale Anweisungen wirken immer bis zum Ende der SAS-Sitzung. Wenn eine globale Anweisung innerhalb eines Schritts platziert wird, entsteht der falsche Eindruck, die Anweisung sei lokal zum betreffenden Schritt.
Beispiel
zu vermeidendes Beispiel
Wenn eine Anweisung mehr als zwei Objekte (Variablennamen, Dateinamen, Makroparameter etc.) enthält, wird jedes Objekt auf eine neue Zeile geschrieben und die Anweisung wird so formatiert, dass man ohne weiteres neue Objekte hinzufügen oder vorhandene löschen kann, ohne die Anweisung insgesamt zu verändern. Das bedeutet auch, dass man das schließende Semikolon auf eine eigene Zeile schreibt und dass man in durch Kommata getrennten Listen die Kommata jeweils an den Beginn jeder Zeile statt an das Ende schreibt.
Begründung: Dadurch wird es einfacher, bestehenden Code zu überarbeiten, insbesondere, weitere Variablen hinzuzunehmen oder auch Variablen von einer Anweisung in eine andere zu kopieren. Auch kann man einfacher eines oder mehrere Objekte innerhalb einer Anweisung durch /* */ auskommentieren.
Beispiel im DATA-Schritt
mit ATTRIB wird es noch übersichtlicher
Beispiel für SQL
Beispiel für Makro-Aufruf:
so sollte man es dagegen nicht machen
und so auch nicht
Wo im DATA-Schritt ein DO-Block stehen kann, steht auch ein DO-Block: Jede bedingte Anweisung (nach THEN oder ELSE) und jede Anweisung nach WHEN oder OTHERWISE erhält einen DO-Block, auch wenn es nicht nötig wäre, da es sich nur um eine Anweisung handelt. Analog gilt das auch für bedingte Makro-Anweisungen nach %THEN und %ELSE.
Begründung: Man muss zwar manchmal eine Anweisung mehr schreiben, dafür spart man eine Codiervariante ein und kann das Programm einfacher überarbeiten, indem man Anweisungen zwischen DO/END-Blöcken kopiert. Bei bedingten Makro-Anweisungen gibt es noch einen Grund mehr, man vergisst nämlich sonst leicht ein Semikolon, siehe untenstehendes Beispiel.
Beispiel im DATA-Schritt
weniger empfehlenswert
Beispiel im Makrocode
weniger gut wäre hingegen
Bei gleichzeitiger Verwendung mehrerer der Dataset-Optionen keep, drop, rename und where wird folgende Reihenfolge eingehalten: zuerst keep oder drop, dann rename, schließlich where.
Begründung: keep und drop werden von SAS als erstes ausgeführt, dann rename, schließlich where. Daher ist dies auch die richtige Reihenfolge im Code. Benutzt man rename, so muss man bei keep und drop die alten Namen nennen, bei where jedoch die neuen Namen.
Beispiel
Zeichenketten, die mehrfach gebraucht werden oder die sich ändern können, werden an zentraler Stelle Makrovariablen zugewiesen. Dabei werden normalerweise keine Anführungszeichen verwendet. An zentraler Stelle heißt: am Anfang des Programms oder auch in einem zu Beginn der Sitzung auszuführenden Programm, das zentrale Zuweisungen enthält.
Begründung: Redundantes pflegen von Informationen an verschiedenen Stellen im Programm führt leicht zu Fehlern, weil man leicht eine Stelle vergisst. Wenn die Zuweisungen an zentraler Stelle erfolgen, findet man sie leichter.
Anführungszeichen sollte man weglassen, weil man dann mit den Inhalten der Makrovariablen flexibler umgehen kann. Zum Beispiel kann man sie dann einfacher mit anderen Strings verketten.
Beispiel
so lieber nicht
Referenzen auf Makrovariablen werden immer mit einem Punkt abgeschlossen.
Begründung: Der Punkt am Ende einer Makrovariablenreferenz zeigt das Ende des Makrovariablennamens an. In manchen Situationen führt ein vergessener Punkt zu einer unerwünschten Interpretation durch den Makroprozessor. Wenn man immer einen Punkt setzt, kann einem das nicht passieren.
Beispiel
&name_1 würde die Makrovariable name_1 referenzieren. Wenn man auch in den anderen Fällen, nämlich bei &name. und bei (&num.) den Punkt schreibt, vermeidet man Fehler durch Vergessen des Punkts.
folgendes Beispiel funktioniert auch, sollte aber vermieden werden
Eingeschlossene Programmzeilen werden gegenüber umschließenden Programmzeilen eingerückt, siehe die folgenden Seiten. Die Einrücktiefe beträgt zwei bis vier Zeichen pro Einrückung. Es erscheint nicht sinnvoll, die Einrücktiefe weiter zu reglementieren.
Begründung:
Weitere Hinweise:
Beispiel mit zwei Zeichen Einrückung
Beispiel mit zwei Zeichen Einrückung
Beispiel mit vier Zeichen Einrückung
schlechtes Beispiel ohne Einrückung
data und run werden nicht eingerückt (außer in Makros), Anweisungen innerhalb des Data-Schritts werden eine Ebene eingerückt. proc und run bzw. quit werden nicht eingerückt (außer in Makros), Anweisungen innerhalb des Proc-Schritts werden eine Ebene eingerückt.
Begründung: Dadurch wird besser sichbar, welche Anweisungen zu einem Schritt gehören und dass die Anweisungen eines Schritts von SAS immer als eine ausführbare Einheit behandelt werden.
Beispiel
weniger übersichtlich ist hingegen
IF und THEN und END stehen aussen, der Rest (die Befehle vom then-Zweig) eine Ebene (2 Leer-Zeichen) eingerückt. Das DO nach dem THEN steht auch direkt nach dem THEN.
ELSE und END stehen aussen, der Rest (die Befehle vom else-Zweig) eine Ebene (2 Leer-Zeichen) eingerückt.
Das DO nach dem ELSE steht auch direkt nach dem ELSE.
Mehrfach-Abfragen nach dem Muster
"Entweder rot dann befehl1, oder wenn gelb dann befehl2 oder wenn grün dann befehl3 oder sonst dann befehl4"
bestehen aus
- dem ersten IF-THEN-DO-END-Block, s.o.
- aus vielen ELSE-IF-THEN-DO-END-Blöcken, s.u.
- und dem letzten ELSE-DO-END-Block, s.o.
für die vielen ELSE-IF-Blöcke gilt jeweils: "ELSE IF" und THEN und END stehen aussen, der Rest (die Befehle vom X-ten-then-Zweig) eine Ebene (2 Leer-Zeichen) eingerückt. Das DO nach dem THEN steht auch direkt nach dem THEN.
Das Semikolon nach einem "langen" Befehl steht immer in einer Extra-Zeile in der gleichen Spalte wie das Schlüsselwort, siehe der set-Befehl bei "gut"es Beispiel .
%macro und %mend stehen aussen, der Rest (%if-%then-%else, DATA-/PROC-Steps, %let, ...) eine Ebene (2 Leer-Zeichen) eingerückt
%if-%then-%else haben die gleichen Einrück-Regeln wie die SAS-Base Kontroll-Strukturen.
Macro-Code ist nicht als eigenständig zu sehen, sondern als Sprach-Erweiterung von SAS-Base.
Das heißt, dass Makro-if-then-else genauso eingerückt werden wie Base-if-then-else:
Makro-if-then-else stehen immer relativ zur Vorgänger-Zeile 2 (oder 3) Zeichen eingerückt.
Das gleiche gilt für Macro-do-end-Schleifen:
Macro-do-end-Schleifen stehen immer relativ zur Vorgänger-Zeile 2 (oder 3) Zeichen eingerückt.
Wenn die Makro-Definition global ist, steht sie aussen. Beispiel
Die Diskussion die sich unter
SAS-Programmierrichtlinien » Codelayout » Platzieren von Anweisungen » DO-Blöcke verwenden (AndreasMangold, 8 März, 2006 - 21:44)
entwickelt hat, speziell
gehört "eigentlich" hier rein, bloß wie ....?
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.
Anleitung, wie jedes Redscope-Mitglied die Programmierrichtlinien bearbeiten kann.
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:
Das in diesem Ablauf mehrfach aufgerufene Makro rdsYalan ist dann - etwas gekürzt:
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
Wo sollen / müssen / dürfen Kommentare stehen, wann verwendet man welche Form von Kommentaren? Sind Kommentare dazu da, dem nicht SAS-Kundigen das Programm zu erklären? Welche zusätzlichen Informationen sollen Kommentare enthalten? Wie sieht ein sauberer Kommentar-Programmkopf aus?
Anleitung, wie jedes Redscope-Mitglied die Programmierrichtlinien bearbeiten kann.
Programme müssen eine Geschichte erzählen
(ist eine vor Jahren mal gelesenene Weisheit)
Das meint:
Die Kommentare in einem Programm enthalten "die Prosa", damit alles zusammen (Code mit den jeweiligen Kommentaren) die "Geschichte" ergibt.
Denn die Programme müssen die Geschichte freiwillig erzählen, man soll ihnen den Sinn nicht mühsam abringen müssen (wie beim z.B. Marx'chen Kapital o.ä. Werken).
Für mich ist eine Methode: Was brauche ich für Infos, damit ich auch nach drei Monaten Urlaub das Programm/den Code-Abschnitt immer noch verstehe.
Man muss ein Prgramm nicht leicht und flüssig lesen könne wie z.B. gewisse Boulevard-Blätter. Aber den Sinn müssen sie "freiwillig" offenbaren!
Wir drucken z.B. unseren Programm-Code (wenn überhaupt) mit Schriftgröße 6 Punkt (Schriftart Courier New). Das kann man nicht leicht lesen, aber man soll es leicht verstehen können.
Ein Beispiel:
/* Sinn */ /* Unsinn */ lohn=lohn*1.05; /* 5% Tarif Erh. */ a=a*1.05; /* a mal 1,05 */
Kommentare immer mit /* Kommentar-Text */.
Die Version mit * Kommentar-Text; ist zu fehleranfällig.
An sich stimme ich dieser Regel zu, und verwende selber beim Programmieren fast nie die *;-Kommentare, da man (wie angesprochen) den Strichpunkt am Ende des Kommentars doch recht schnell vergisst (vor allem wenn man auch andere Programmiersprachen gewöhnt ist...)
Allerdings sollte man auch einen gravierenden Nachteil dieser Regel nicht außer Acht lassen: Gerade bei der Fehlersuche hat man häufig dass Problem, dass man größere Codeabschnitte auskommentieren will. Wenn man aber in einem solchen Abschnitt Blockkommentare der Form /* ... Kommentar... */ verwendet, ist das nicht mehr möglich.
Gibt es Vorschläge zur Lösung dieses Problems? Als Workaround kann man natürlich das Pseudo-Auskommentieren mittels %MACRO / %MEND verwenden, aber das ist jetzt nicht unbedingt guter Programmierstil :-) Ideal wäre natürlich, wenn SAS irgendwann einmal auch Zeilenkommentare im C++/Java-Style zulassen würde (mit // am Anfang).
Wie sollen Dateien, Variablen, Makros, Makrovariablen benannt werden? Sind Namenskonventionen, die den Datentyp dem Variablennamen voranstellen, auf SAS anwendbar? Sollen Namen Unterstriche enthalten oder gemischt groß und kleine geschrieben werden?
Anleitung, wie jedes Redscope-Mitglied die Programmierrichtlinien bearbeiten kann.
Da SAS im Gegensatz zu vielen anderen Programmiersprachen im Programmcode nicht zwischen Groß-/Kleinschreibung unterscheidet, ist es letztendlich zweitrangig, ob man durchgängige Konventionen bei der Groß-/Kleinschreibung beachtet oder nicht - das Programm läuft so oder so. Im Sinne der Lesbarkeit des Programmcodes ist es aber schon sinnvoll, wenn man bestimmte Regeln einhält.
Ich habe mir folgende Konventionen angewöhnt, die sich für mich persönlich bei der Entwicklung von SAS-Programmen auch bewährt haben:
Als Beispiel:
DATA MeineLib.MeineDatei;
DO Variable = 1 TO 100;
VariableQuadrat = Variable**2;
OUTPUT;
END;
RUN;
Vorteil dabei ist, das man sofort sieht, welche Namen selbst gewählt und welche durch die SAS-Syntax vorgegeben sind - das erleichtert das Lesen insbesondere dann, wenn man nicht sämtliche Options des Data Step oder einer bestimmten Prozedur auswendig kennt.
Schließlich noch eine weitere Regel, die aber vermutlich eher für einen kleineren Kreis von Programmierern relevant ist:
Ich habe häufig die Situation, dass ich in einem .SAS-Programmfile drei Programmiersprachen mische - nämlich SAS/BASE, SQL und IML. Nun möchte ich gerne an jeder Programmstelle sofort erkennen können, in welchem sprachlichen Kontext ich mich gerade bewege - auch dann, wenn das einleitende DATA, PROC SQL oder PROC IML ein paar Seiten weiter oben im Quelltext steht. Hierfür habe ich mir folgende Konvention angewöhnt:
Beispiel:
DATA MeineLib.MeineDatei;
DO Variable = 1 TO 100;
VariableQuadrat = Variable**2;
OUTPUT;
END;
RUN;
PROC IML;
VariableQuadrat = j(100, 1, .);
do Variable = 1 to 100;
VariableQuadrat[Variable] = Variable**2;
end;
create MeineLib.MeineDatei var {VariableQuadrat};
append;
QUIT;
(Das Beispiel ist zugegebenermaßen nicht das beste, in IML lässt sich das gleiche Ergebnis ohne Schleife mit besserer Perfomance erzielen, aber hier geht es um den direkten Vergleich zum Data Step...)
Bei der Benennung von Hilfsvariablen, Datasets mit temporären Zwischenergebnissen, temporär benötigten File- oder Libnames, Hilfsmakros oder -Modulen, etc. sollte man darauf achten, dass diese nicht mit etwa vorhandenen Objekten kollidieren. Dazu bietet es sich an, durchweg ein bestimmtes Präfix wie "_" oder "tmp_" oder "meinmakro_" zu verwenden.
Bei (temporären) Hilfs-Variablen, insbesondere bei Schleifenzählern, hat es sich sehr bewährt nie einstellige Variablennamen zu vergeben!
Diese Regel gilt ganz unabhängig von dem "Unterstrich im Namen"-Tipp (Dazu bietet es sich an, durchweg ein bestimmtes Präfix wie "_" oder "tmp_" oder "meinmakro_" zu verwenden) aus dem übergeordneten Eintrag Hilfs- und temporäre Objekte.
Beispiel
Makroparameter mit SAS-üblichen Funktionen sollten auch den SAS-üblichen Namen tragen und als Schlüsselwort-Parameter implementiert sein, z.B.
| Eingangs-Dataset | data=
| Ausgangs-Dataset | out=
| Analysevariablenliste | var=
| Gruppierungsvariablenliste | by=
| Klassifizierungsvariablenliste | class=
| Vorbedingung | where=
| Einlese-Datei | infile=
| Auslese-Datei | file=
| Bibliothek | lib=
| Überschrift | title=
Das macht natürlich mehr Sinn, wenn man durchgängig englischsprachig bleibt, was ich daher auch empfehle.
Fehler, die man mehr als einmal macht oder nach denen man lange suchen muss, sind besonders ärgerlich. Da ist es schon besser, wenn man als Anfänger diese Fehler gar nicht machen muss, weil man von vornherein auf die Fallen hingewiesen wird.
In manche Fallen kann man bei allen Programmiersprachen tappen, beispielsweise im Bereich der Schleifenprogrammierung (z.B. Schleifenkontrollvariable versehentlich modifiziert). Andere Fallen gibt es so nur bei SAS (z.B. fehlende LENGTH-Anweisung bei alphanumerischen Variablen).
Anleitung, wie jedes Redscope-Mitglied die Programmierrichtlinien bearbeiten kann.
Die SAS-Rückgabewerte (unter UNIX bzw. generell) sollten zur Fehlervermeidung ausgewertet werden.
Das dient der Fehlervermeidung, denn das "Nicht-Bemerken" von Fehlern und weiter arbeiten mit falschen (Zwischen-) Ergebnissen ist sehr schlecht.
Das gleiche gilt für die Analyse des SAS-LOGs (LOG-Fenster im SAS Display Manager oder LOG-Datei bei Aufruf von SAS als Batch-Programm. Im Idealfall sollte die Log-Analyse automatisch erfolgen.
Siehe auch:
Redscope.org » Foren » ETL & Base SAS » Die Perfektionierung des Durchsuchen von SAS-Logs nach Fehlern (HansKneilmann, 4 April, 2006 - 16:25)
oder
Redscope.org » Projekte » Yalan - Yet another Log Analyzer (StephanFrenzel, 15 Oktober, 2005 - 18:07)
Nach jedem "spannenden" Teil eines Skripts (Datenschritte oder Makroaufrufe) sollten Systemvariablen getestet und entsprechende reagiert werden. Kandidaten wären:
- SYSERR
- SYSINFO
- ...
Das erspart viel Fehlersuche.
Folgende weitere Systemvariablen sollten zur Fehlervermeidung/Fehlererkennung geprüft werden:
SYSRC nach jedem X-Befehl
(X-Befehl setzt Kommando ans Betriebssystem ab)
SYSFILRC nach jedem filename-Befehl
(Zuweisung logischer Datei-Name zu phys. Datei auf der Festplatte)
SYSLIBRC nach jedem libname-Befehl
(Zuweisung logischer libref-Name zu phys. Ordner/phys. directory im Dateisystem)
Beispiel:
%macro create_L(l_name, l_path, Vers=);
/*---------------------------------------------------------------------------
* macht Libref-Definition, mit Fehler-Analyse und Meldung
* macht also: libname ;
* Beispiele:
* %create_L(xx_prog, c:\sas_mdw\dw_prog);
* %create_L(xx_prog, c:\sas_mdw\dw_prog, Vers=v8);
*---------------------------------------------------------------------------*/
%put INFO: macro create_L( l_name=&l_name., l_path=&l_path., Vers=&VERS.);
%if &SYSVER. eq 6.12 %then %do;
%if &VERS. ne %then %do;
%put INFO: macro create_L, reset Vers=&VERS., SYSVER=&SYSVER.=6.12;
%let Vers=;
%end;
%end;
libname &l_name. &VERS. "&l_path.";
%if &syslibrc ne 0 /* Wenn Verzeichnis fehlt, dann melden */
%then %do;
%let l_path=%sysfunc(translate(&l_path., '/', '\')); /* Tausche \ gegen / (gehen sonst */
/* verloren, fehlen z.B. in email) */
%let errmsg=Verzeichnis l_path=&l_path. für Lib=&l_name. fehlt ;
%put %substr(###ERROR, 4)%str(:) &errmsg.;
%end;
%mend create_L;
Mit welchen Situationen sollten Codes und Makros zurechtkommen, die zur einigermaßen allgemeinen Benutzung gedacht sind, und wie kann man dies erreichen?
Beispiele:
* Wenn keine Plattform-spezifischen Dinge verwendet werden müssen, sollte Code portabel sein, d.h. auf verschiedenen Betriebssystemen laufen.
* Wenn möglich, sollten Makroparameter vom Type "Dataset" oder "Variablenliste" nicht nur mit Data Files und einfachen Listen zurechtkommen, sondern auch mit Data Views, Dataset-Optionen, komplexen Variablenlisten a là "a1-a100 c--f h:"
* Wenn benötigte Verzeichnisse nicht existieren, sollten Sie evtl. automatisch angelegt werden
* ...
slashes statt Backslashes
Hierbei muss berücksichtigt werden, dass der Makroaufruf hinter then oder else stehen könnte. Also den Makrocode stets mit do; beginnen und mit end bzw. end; beenden:
end ohne Semikolon verwendet werden, wenn wie hier Makroaufrufe mit Semikolon beendet werden (obwohl das nicht nötig wäre), da sonst ein evtl. anschließender else-Zweig wegen des doppelten Semikolons nicht korrekt erkannt würde.Was gibt es sonst noch zu beachten? Zum Beispiel, dass man Programmteile löschen sollte, die nicht mehr benötigt werden.
Anleitung, wie jedes Redscope-Mitglied die Programmierrichtlinien bearbeiten kann.
Metaregeln sollen den Umgang mit Programmierrichtlinien im Alltag einfacher machen: Wann darf man von den Regeln abweichen? Wie stellt man sicher, dass die Programmierrichtlinien auch eingehalten werden? Welche Bedeutung hat der individuelle Programmierstil? Wie entwickelt man firmenspezifische Richtlinien?
Anleitung zum Bearbeiten der Programmierrichtlinien für jedes Redscope-Mitglied.