ABAP - Schlüsselwortdokumentation →  ABAP - Programmierrichtlinien →  Aufbau und Stil →  Namensgebung → 

Programminterne Namen

Hintergrund

Programminterne Namen bezeichnen Entitäten, die in einem Programm deklariert werden und innerhalb des Programms oder auch aus anderen Programmen heraus angesprochen werden können. Beispiele sind die Bezeichner von Datentypen und Datenobjekten sowie Methoden und ihre Schnittstellenparameter.

Programminterne Deklarationen können in verschiedenen Kontexten vorgenommen werden, die alle einen eigenen Namensraum aufspannen. Diese Kontexte sind in der Reihenfolge von lokal nach global:

  1. lokale Deklarationen in einer Prozedur (Methode)
  2. Deklarationen von Instanzkomponenten und statischen Komponenten in einer Klasse
  3. globale Deklarationen im Deklarationsteil eines Programms

Dabei verdecken lokale Deklarationen immer die globaleren Deklarationen der darüberliegenden Kontexte. Verschiedenartige Deklarationen spannen in ihrem Kontext nochmals einen eigenen Namensraum auf, mit der Ausnahme, dass alle Komponenten einer Klasse unabhängig von ihrer Art in einem einzigen Namensraum liegen.

Die in ABAP-Programmen verwendbaren Bezeichner unterliegen gemäß Regel ABAP Objects verwenden, und Regel Standardeinstellungen für Programmattribute übernehmen, prinzipiell den syntaktischen Vorschriften für Klassen, das heißt sie müssen mit einem Buchstaben beginnen, dem weitere Buchstaben und Ziffern folgen, die durch Unterstriche getrennt sein können.

Regel

Verwechslungen und ungewollte Verschattungen bei programminternen Deklarationen vermeiden

Wählen Sie programminterne Namen so, dass es nicht zu Verwechslungen mit ABAP-Wörtern, anderen Deklarationen oder zur ungewollten Verschattung eines globaleren Namens durch einen lokalen Namen kommt. Hierzu sollten globale Entitäten und Schnittstellenparameter von Prozeduren durch ein Präfix gekennzeichnet werden.

Details

Neben der allgemeingültigen Regel sprechende Namen zu vergeben muss für programminterne Deklarationen auch obige Regel zur Vermeidung von Verwechslungen durch menschliche Leser beachtet werden (Der Compiler weiß anders als ein menschlicher Leser dagegen in der Regel genau, was hinter einem Bezeichner steckt.). Durch Einsatz der folgenden Präfixe wird sowohl die Gefahr der ungewollten Verschattung als auch eine Verwechslungsgefahr gebannt:

Weitere Maßnahmen sind die Verwendung zusammengesetzter Bezeichner und der Einsatz von Komponentenselektoren.

Im Folgenden werden die verschiedenen Aspekte der programminternen Namensgebung ausführlich und systematisch diskutiert.

Verwechslung mit ABAP-Wörtern

Eine Grundregel in fast allen Vorgaben zur Namensgebung besteht darin, dass die Anweisungen der Sprache nicht als Bezeichner im Quelltext verwendet werden dürfen, soweit dies überhaupt syntaktisch erlaubt ist. Diese Maßnahme dient zur Erhöhung der Lesbarkeit, indem eine Verwechslung zwischen Anweisungen und Bezeichnern verhindert wird. In ABAP lässt sich eine solche Regelung jedoch kaum konsequent durchhalten, da hier der Wortschatz der Programmiersprache sehr groß ist und auch noch ständig anwächst. Ein Entwickler kennt im Allgemeinen nie sämtliche in allen Anweisungen und Anweisungszusätzen vorkommenden ABAP-Wörter auswendig, und er kann auch gar nicht wissen, welche Wörter eventuell noch hinzukommen.

Aus diesem Grund ist ein vollkommenes Verbot von ABAP-Wörtern (ABAP-Schlüsselwörter oder Zusätze) als Bezeichner weder sinnvoll noch durchführbar. Durch die farbliche Unterscheidung im ABAP Editor und durch die durch Verwendung des Pretty Printers unterschiedliche Groß- und Kleinschreibung für Operanden und ABAP-Wörter besteht in der Regel auch keine Gefahr von Verwechslungen. Im Zweifelsfall kann zur Verdeutlichung auch immer das Fluchtsymbol (!) vor einen Bezeichner geschrieben werden, um diesen von einem gleichnamigen ABAP-Wort in der Anweisung zu unterscheiden.

Ein einzelnes ABAP-Wort stellt in der Regel aber keinen sprechenden Bezeichner dar. Es ist daher guter Stil, ABAP-Wörter nur im Rahmen zusammengesetzter Bezeichner mit Unterstrichen (_) zu verwenden, wie zum Beispiel account_class anstatt einfach class. Da der Unterstrich in den meisten ABAP-Wörtern nicht vorkommt, ist er in aller Regel auch ein gutes Unterscheidungsmerkmal zwischen solchen und Bezeichnern. In wenigen, ganz seltenen Fällen kann der Compiler ein ABAP-Wort nicht von einem gleichnamigen Bezeichner unterscheiden. In diesen Fällen ist die Angabe des Fluchtsymbols (!) sogar notwendig.

Verwechslung zwischen verschiedenen Deklarationen

In Klassen liegen alle Komponenten im selben Namensraum. In einer Klasse kann es daher beispielsweise keine gleichnamigen Datentypen und Attribute geben, sodass es hier zu keinen Verwechslungen kommen kann. In den anderen Kontexten, das heißt innerhalb von Prozeduren ( Methoden) oder für die globalen Deklarationen eines ABAP-Programms, spannen verschiedene Deklarationen auch verschiedene Namensräume auf. Es kann hier beispielsweise gleichnamige Datenobjekte und Datentypen geben. Objekttypen, das heißt lokale Klassen und Interfaces, liegen dabei im selben Namensraum wie Datentypen.

Damit es auf der Seite des Betrachters zu keinen Verwechslungen kommt, empfehlen wir, für unterschiedliche Entitäten auch unterschiedliche Bezeichner zu verwenden, insbesondere Datenobjekte nicht mit den gleichen Bezeichnern wie Datentypen zu versehen. Ausnahmen von dieser Regel können Fälle sein, in denen die Bedeutung eines Bezeichners absolut klar ist, zum Beispiel bei der Deklaration einer Hilfsvariablen wie:

DATA i TYPE i.

Was aber umgekehrt nie vorkommen sollte, ist die Bezeichnung eines Datenobjektes mit dem Namen eines Datentyps, der nicht der Typ des Objektes ist:

DATA i     TYPE f.
DATA tadir TYPE trdir.

Solche Deklarationen sind verwirrend und daher gefährlich!

Verschattung globalerer Deklarationen

Die Bezeichner in lokalen Kontexten verschatten gleichartige Deklarationen in globaleren Kontexten. Beispielsweise verschattet ein mit TYPES deklarierter Datentyp in einer Methode einen gleichnamigen Datentyp der Klasse, dieser einen gleichnamigen Datentyp des Programms und dieser wiederum einen gleichnamigen Datentyp aus dem ABAP Dictionary.

Entwickler müssen dafür sorgen, dass kein globaleres Objekt verdeckt wird, das im aktuellen Kontext verwendet werden soll. Umgekehrt muss verhindert werden, dass aus Versehen ein globales Objekt verwendet wird, wo ein lokales gemeint war. Dem Leser eines Quelltextabschnitts sollte gleichfalls immer klar sein, worauf sich ein Bezeichner bezieht. Es sollte bei der Namensgebung demnach darauf geachtet werden, dass lokale Bezeichner, soweit möglich, keine globaleren Bezeichner verdecken.

Im Sinne des KISS-Prinzips schlagen wir vor, dass sich die lokalen Bezeichner einfach dadurch von globalen Bezeichnern unterscheiden, dass sie nicht deren Konventionen folgen, wobei hier hauptsächlich die Bezeichner in globalen Deklarationen des aktuellen Programms oder im Repository gemeint sind. Eine lokale Klasse sollte also beispielsweise nie mit dem Präfix cl_ beginnen, ein lokales Interface nie mit dem Präfix if_ und ein lokales Datenobjekt nie mit dem Präfix g_.

In einer Methode (in neuen Funktionsbausteinen und Unterprogrammen sollte es keine lokalen Deklarationen mehr geben) besteht Verwechslungsgefahr zwischen lokalen Bezeichnern inklusive Schnittstellenparametern und globaleren Bezeichnern sowie zwischen Deklarationen innerhalb der Implementierung und den Schnittstellenparametern.
Eine Verwechslung lokaler Datenobjekte in einer Methode mit Komponenten der eigenen Klasse kann immer dadurch ausgeschlossen werden, dass Klassenkomponenten explizit über den Namen der Klasse und den Klassenkomponentenselektor (=>) oder über die Objektreferenzvariable me und den Instanzkomponentenselektor (->) angesprochen werden.
Insbesondere sollten auch bei Verwechslungsgefahr mit eventuellen gleichnamigen eingebauten Funktionen die funktionalen Methoden der eigenen Klasse bei einer Verwendung an einer Operandenposition nur über einen der Selektoren angesprochen werden (Bei zu exzessiver Verwendung von Selektoren kann die Lesbarkeit des Quelltextes allerdings auch wieder leiden, weshalb hier jeweils eine individuelle Abwägung zu treffen ist.). Verwechslungsgefahr besteht aber höchstens bei kurzen Methodennamen. Bei Methoden, deren Name aus mehreren Wörtern zusammengesetzt ist oder mit den Präfixen set_, get_ oder is_ beginnt, besteht im Allgemeinen keine solche Verwechslungsgefahr. Da Methoden immer eine überschaubare Größe haben sollen und so immer alle Deklarationen für einen Leser sichtbar sind, sollte diese einfache Regel für die Lesbarkeit einer Methode ausreichend sein.
Ist bei einer Methodenimplementierung die Deklaration der Parameterschnittstelle der Methode (wie in lokalen Klassen) nicht sichtbar, ist eine zusätzliche Unterscheidung zwischen den lokalen Daten und Schnittstellenparametern sinnvoll. Hierfür haben sich die eingangs genannten Präfixe eingebürgert. Ein weiterer Präfixbestandteil l für die lokalen Daten könnte eventuell auch noch in Erwägung gezogen werden, stellt aber letztendlich eine redundante Information dar.
Bei der Verwendung von Klassenkomponenten kann eine Verwechslungsgefahr stets ausgeschlossen werden, indem sie über den Namen der Klasse und den Klassenkomponentenselektor (=>) bzw. eine Objektreferenzvariable und den Instanzkomponentenselektor (->) angesprochen werden. Die Einführung einer diesbezüglichen Namenskonvention würde redundante Information bedeuten, die der Lesbarkeit nicht förderlich wäre und dem grundlegenden KISS-Prinzip widersprechen würde. Dies gilt insbesondere für die funktionalen Methoden. Diese verdecken zwar gleichnamige eingebaute Funktionen, eine Einführung eines Präfixes, das eine funktionale Methode als Methode einer Klasse auszeichnet, wäre aber höchst unüblich.
Im globalen Deklarationsteil eines Programms können lokale Klassen und Interfaces sowie globale Datentypen und Datenobjekte angelegt werden.

Anmerkung

Für Bezeichner innerhalb des Quelltextes werden häufig Namenskonventionen etabliert, die genaue Vorschriften zur Namensbildung einschließlich etwaiger Prä- und Suffixe aufstellen. Solche Vorschriften verlieren sich oft in übertriebener formalistischer Strenge, und so gebildete Namen enthalten redundante Informationen, sind kaum wartbar und werden dabei dem obersten Ziel, nämlich der Lesbarkeit und selbstdokumentierender Quellen, oft nicht gerecht. Wir haben uns hier daher auf die in unseren Augen essenziellen und universellen Punkte bei der Namensgebung beschränkt. Darüber hinausgehende Regelungen sind nur auf der Ebene von Entwicklungsgruppen oder -organisationen sinnvoll.

Insbesondere bei der Verwendung von Prä- und/oder Suffixen ist es zwar weit verbreitet, in diesen die technischen Eigenschaften des bezeichneten Objektes abzulegen. Abgesehen davon, dass wir die Angabe technischer Informationen im Namen ohnehin nicht für notwendig halten, gibt es in ABAP so viele technische Eigenschaften eines Objektes, dass diese nicht durch einfache Regeln für kurze Prä- und/oder Suffixe abbildbar bzw. dass Kombinationen verschiedener technischer Zusätze oft nicht eindeutig zu interpretieren sind. Einige Beispiele:

Völlig irreführend wäre es, die statischen Attribute von Klassen durch ein Präfix g_ als global zu kennzeichnen. Sie sind nur innerhalb der Klasse gültig und haben daher eine vollkommen andere Semantik als globale Datenobjekte. Insbesondere deutet ihre Verwendung nicht auf eine Designschwäche hin, wie es bei globalen Datenobjekten aus heutiger Sicht im Allgemeinen der Fall ist.

Wir empfehlen daher zusammengefasst einen eher zurückhaltenden Einsatz von Namenszusätzen, insbesondere solcher mit technischen Informationen. Natürlich steht es jeder Organisation frei, sich dennoch für solche Konventionen zu entscheiden, die unsere Grundregeln ergänzen können. Gerade im ABAP-Umfeld mit seiner großen Typvielfalt, seinen vielen Kontexten, der Unterscheidung zwischen Referenz- und Wertübergabe etc. dürfte es aber kein leichtes Unterfangen sein, ein vollständiges, in sich geschlossenes, widerspruchfreies, technisch korrektes und vor allen Dingen dann auch noch leicht verständliches Regelwerk für Präfixe und Suffixe zu erstellen. Die uns bekannten Ergebnisse sind dann doch reine Konvention, meistens nicht vollständig und teilweise nicht immer sinnvoll.

Schlechtes Beispiel

Das Beispiel in folgendem Quelltext demonstriert die Verschattung von Bezeichnern in verschiedenen Kontexten. Dass hier aus Gründen der Einfachheit keine sprechenden Namen für die Datenobjekte gewählt wurden, kann außer Acht gelassen werden.

DATA a1 TYPE string VALUE `a1 global`.
DATA a2 TYPE string VALUE `a2 global`.
DATA a3 TYPE string VALUE `a3 global`.
DATA a4 TYPE string VALUE `a4 global`.
DATA a5 TYPE string VALUE `a5 global`.
CLASS demo DEFINITION.
  PUBLIC SECTION.
    METHODS main
      IMPORTING a1 TYPE string DEFAULT 'a1 imported'
      RETURNING value(a6) TYPE string.
    CLASS-DATA a1  TYPE string VALUE `a1 class`.
    CLASS-DATA a2  TYPE string VALUE `a2 class`.
    DATA a3        TYPE string VALUE `a3 class`.
    DATA a4        TYPE string VALUE `a4 class`.
ENDCLASS.
CLASS demo IMPLEMENTATION.
  METHOD main.
    DATA a3 TYPE string VALUE `a3 local`.
    DATA a4 TYPE string VALUE `a4 local`.
    CONCATENATE a1 demo=>a2 me->a3 a4 a5
      INTO a6 SEPARATED BY `, `.
  ENDMETHOD.
ENDCLASS.

Wenn wir die Implementierung der Methode main allein betrachten, ist in der Anweisung CONCATENATE nur für die Operanden demo=>a2 und me->a3 klar ersichtlich, dass es sich um Attribute der Klasse handelt und dass a4 ein lokales Datenobjekt der Methode ist. Nur in der Gesamtübersicht ist zu erkennen, dass a1 einen Importing-Parameter, a5 ein globales Datenobjekt des Programms und a6 einen Returning-Parameter bezeichnet. Die globalen Datenobjekte a1 bis a4 sind in der Methode überhaupt nicht adressierbar, da sie durch lokale Datenobjekte bzw. Attribute der Klasse verschattet sind.

Gutes Beispiel

In folgendem Quelltext wurden im Vergleich zu obigem Quelltext die zuvor diskutierten Präfixe eingeführt, um Verschattungen zu vermeiden und Schnittstellenparameter von lokalen Datenobjekten zu unterscheiden. Auf sprechende Namen wurde hier wieder verzichtet, um den Blick auf das für dieses Beispiel Wesentliche zu lenken.

DATA g_a1 TYPE string VALUE `g_a1 global`.
DATA g_a2 TYPE string VALUE `g_a2 global`.
DATA g_a3 TYPE string VALUE `g_a3 global`.
DATA g_a4 TYPE string VALUE `g_a4 global`.
DATA g_a5 TYPE string VALUE `g_a5 global`.
CLASS demo DEFINITION.
  PUBLIC SECTION.
    METHODS main
      IMPORTING i_a1 TYPE string DEFAULT 'i_a1 imported'
      RETURNING value(r_a6) TYPE string.
    CLASS-DATA a1 TYPE string VALUE `a1 class`.
    CLASS-DATA a2 TYPE string VALUE `a2 class`.
    DATA a3       TYPE string VALUE `a3 class`.
    DATA a4       TYPE string VALUE `a4 class`.
ENDCLASS.
CLASS demo IMPLEMENTATION.
  METHOD main.
    DATA a3 TYPE string VALUE `a3 local`.
    DATA a4 TYPE string VALUE `a4 local`.
    CONCATENATE i_a1 demo=>a2 me->a3 a4 g_a5
     INTO r_a6 SEPARATED BY `, `.
  ENDMETHOD.
ENDCLASS.

In der CONCATENATE-Anweisung sind jetzt alle Operanden klar erkennbar. Die Einführung eines Präfixes l_ für die lokalen Bezeichner wäre möglich, ist aber aus zwei Gründen unnötig:

Mit der hier verwendeten minimalen Namenskonvention sind in der Methode alle im gezeigten Quelltextabschnitt deklarierten Datenobjekte adressierbar. Die Deklaration der globalen Datenobjekte erfolgt natürlich nur zur Demonstration der Verschattung und ihrer Vermeidung. In Programmen, die nicht mit klassischen Dynpros arbeiten, sollten sie nicht mehr vorkommen.