Zur Sinnhaftigkeit der Camel-Case-Konvention
Einleitung
In Codekonventionen zu populären Programmiersprachen wie Java und Sprachen für das .NET Framework wird die Camel-Case-Konvention zur Benennung für verschiedene Arten von Bezeichnern, etwa privaten Variablen, ohne Angabe ihrer Vorteile gegenüber anderen Konventionen empfohlen. Dieser Artikel liefert eine Beschreibung der Camel-Case-Konvention und setzt sich damit kritisch aus Sicht von Typographie, menschlicher Wahrnehmung und Codierung auseinander. Dabei wird erörtert, inwieweit die Verwendung der Camel-Case-Konvention ein Fehlerpotential in sich birgt. Alternative Konventionen zur Benennung von Bezeichnern werden qualitativ mit der Camel-Case-Konvention verglichen.
Im Folgenden wird, angelehnt an die bei Microsoft üblichen Begriffe, die Bezeichnung Camel Case für Bezeichner der Form userName
und Pascal Case für Bezeichner wie UserName
verwendet.
Camel Case und alternative Konventionen
Die Camel-Case-Benennungskonvention ist eine Übereinkunft zur Benennung von Bezeichnern wie Variablen, Methoden und Methodenparametern. Für sie ist kennzeichnend, daß das erste Zeichen eines Bezeichners grundsätzlich klein geschrieben wird. Innerhalb des Bezeichners werden Groß- und Kleinschreibung gemischt verwendet, wobei das erste Zeichen jedes den Bezeichner konstituierenden Wortes groß geschrieben wird (Beispiele: userName
, deleteUser
, createBankAccount
, logoutAndShutdown
). Die Konvention gewann mit der zunehmenden Verbreitung der Programmiersprache Java an Bedeutung. Sie wird in Java u. a. zur Benennung von privaten und lokalen Variablen, Methodenparametern und Methodennamen vorgeschlagen:
Neben der Camel-Case-Konvention existieren u. a. folgende Konventionen zur Benennung von Bezeichnern, die wahlweise mit Präfices der Konventionen Apps Hungarian oder Systems Hungarian angereichert werden können:
Bei der Pascal-Case-Benennungskonvention werden die den Bezeichner konstituierenden Wörter jeweils groß geschrieben. Beispiele:
UserName
,DeleteUser
,CreateBankAccount
,LogoutAndShutdown
. Die Pascal-Case-Konvention wird z. B. in den Programmiersprachen Pascal und Visual Basic bis Version 6.0 zur Benennung von Typen, Methoden, Eigenschaften und Variablen eingesetzt.In der Programmiersprache C ist die Trennung der den Bezeichner konstituierenden Wörter durch den Unterstrich (»_«) gebräuchlich. Beispiele:
user_name
,delete_user
,create_bank_account
,logout_and_shutdown
,ERROR_SUCCESS
. Die Trennung durch den Unterstrich kann auch mit wechselnder Groß- und Kleinschreibung kombiniert werden.Andere Programmiersprachen, darunter COBOL, erlauben, den Bindestrich (»-«) innerhalb von Bezeichnern zur Trennung der konstituierenden Wörter zu benutzen, ohne daß das Zeichen als Subtraktionsoperator interpretiert wird. Beispiele:
USER-NAME
,DELETE-USER
,CREATE-BANK-ACCOUNT
,LOGOUT-AND-SHUTDOWN
. Eine Variation von Groß- und Kleinschreibung ist hier ebenfalls möglich.
Benennung von Bezeichnern in .NET
Die Programmiersprachen Visual Basic, Visual Basic .NET und C# bieten die Möglichkeit, Attribute einer Klasse als Eigenschaften zu implementieren. In den genannten Programmiersprachen ist zur Benennung von Eigenschaften die Pascal-Case-Konvention gebräuchlich. Der eigentliche Eigenschaftswert, auf den über Zugriffsprozeduren der Eigenschaft zugegriffen wird, ist in einer privaten Variablen abgelegt. Es liegt nahe, Eigenschaft und dazugehörige private Variable so zu benennen, daß ihre Zusammengehörigkeit leicht erkennbar ist.
Entgegen der verbreiteten Ansicht, die Benennung von Bezeichnern in .NET sei als Teil des C#-Standards bei der ECMA International standardisiert, handelt es sich dabei lediglich um einen informellen Teil des Standards. In Version 3.0 des C#-Standards sind Benennungskonventionen nicht einmal mehr direkt enthalten. Stattdessen wird auf die Webversion der separat veröffentlichten Design Guidelines for Class Library Developers verwiesen, die eine mögliche Konvention unter vielen darstellen. Lediglich das Einhalten von Teilen der Konventionen, etwa das Nachstellen des Suffixes »Attribute« bei Attributklassennamen, und der in der CLS spezifizierten Regeln ist zwingend erforderlich, um volle Interoperabilität zwischen Assemblies, die in verschiedenen .NET-Programmiersprachen entwickelt wurden, zu gewährleisten. Die Camel-Case-Konvention wird in den genannten Entwurfsrichtlinien auch zur Bezeichnung von lokalen Variablen und Methodenparametern empfohlen. Die Auswirkungen sind jedoch gering, da Variablennamen im Gegensatz zu Methodennamen nur geringen Einfluß auf das Aussehen von Objektschnittstellen haben.
Die im Kapitel Field Usage Guidelines der .NET Framework General Reference angeführten Beispiele sind ebenfalls schwerlich als Richtschnur für die Benennung von Bezeichnern in eigenen Projekten anzusehen, da es sich bei den Visual-Basic-.NET-Beispielen offensichtlich um automatisch aus den C#-Beispielen erstellten Code handelt, der zudem mehrfach aus eben diesem Grund nicht kompilierbar ist. In den Beispielen im genannten Artikel wird die Camel-Case-Konvention ohne Präfix zur Benennung privater Variablen zur Aufnahme der Eigenschaftswerte, genannt backing fields, benutzt. Im Folgenden wird der relevante Ausschnitt aus dem Kapitel wiedergegeben:
Das Einhalten der Empfehlung, private Variablen, klein zu schreiben (ohne Aussage darüber, welche Zeichen genau klein geschrieben werden sollen), schlägt in Visual Basic .NET fehl, wenn Eigenschaften mit den Namen Url
und DestinationUrl
definiert werden, da deren Namen mit jenen der privaten Variablen url
und destinationUrl
kollidieren. Auch der Hinweis, auf die Verwendung der Ungarischen Notation zu verzichten, ist unzureichend begründet, da die ursprüngliche Form des Apps Hungarian sehrwohl zum Ziel hatte, die Semantik der Variablen auszudrücken. Die dritte Empfehlung, Feldnamen (ohne Aussage darüber, ob lokale Felder oder Felder auf Typebene gemeint sind) keine Präfices voranzustellen, kann ebenfalls nicht für Visual Basic .NET gelten, da eine Unterscheidung zwischen Eigenschaft und dazugehöriger privater Variable nur sinnvoll durch Anhängen eines Präfixes oder Suffixes erzielt werden kann.
Auch der Abschnitt Capitalization Styles der .NET Framework General Reference trifft keine Aussage über die Benennung privater Variablen. Da diese nicht Teil der Schnittstelle eines Typs sind, ist der standardisierten Benennung eine geringe Bedeutung beizumessen. Der bei Microsoft beschäftigte Brad Abrams rät in den von ihm veröffentlichten Microsoft-internen Internal Coding Guidelines und vermutlich auch im von ihm publizierten Buch Framework Design Guidelines dazu, private Felder, welche Eigenschaftswerte speichern, entsprechend der Camel-Case-Konvention zu benennen (Eigenschaft UserName
, private Variable userName
). Daß dies in Visual Basic .NET nicht möglich ist, scheint dem Autor der Konventionen für .NET nicht aufzufallen. So ist es auch nicht weiter verwunderlich, daß die Autoren der Visual-Basic-.NET-Klassenbibliothek Microsoft.VisualBasic.dll
sich nicht an diese vorgeblich für alle .NET-Programmiersprachen vorgesehene Konvention halten.
In C# werden zwei Bezeichner selbst dann als unterschiedlich angesehen, wenn sie sich nur in Groß- und Kleinschreibung unterscheiden. Manche Entwickler nutzen dies aus und geben der privaten Variablen den Namen der dazugehörigen Eigenschaft, wobei das erste Zeichen klein geschrieben wird (Eigenschaft UserName
, private Variable userName
). VB erfordert, daß sich zwei Bezeichner in mehr als der Groß- und Kleinschreibung unterscheiden, um als verschiedene Bezeichner zu gelten. Deshalb wird zusätzlich zur in C# verwendeten Kleinschreibung oder alternativ ein Gültigkeitsbereichspräfix an den Beginn des Bezeichners der privaten Variablen gestellt (Eigenschaft UserName
, private Variable _UserName
, _userName
, m_UserName
oder m_userName
). Die Entwicklungsumgebung für Visual Basic .NET erlaubt das Einblenden von Prozedurtrennlinien. Unterstriche in Variablennamen werden dabei von einer allenfalls vorhandenen Prozedurtrennlinie überdeckt. Die Benennung von Variablen mit einem Unterstrich (_UserName
) als erstes Zeichen erweist sich aus diesem Grund als unpraktisch. Das Voranstellen eines Präfixes wie m_
(m_UserName
) schafft begrenzt Abhilfe.
Probleme der Camel-Case-Konvention
Signifikante Buchstaben in der Typographie
In der deutschen und auch der englischen Schrift kommt dem ersten Buchstaben von Wörtern und Sätzen eine wichtige Bedeutung für die Lesbarkeit und Erfaßbarkeit des Textes zu. In beiden Sprachen werden Sätze immer mit einem Großbuchstaben (Versal) eingeleitet, auch wenn das erste Wort im Satz bei Vorkommen innerhalb eines Satzes klein geschrieben würde. Im Deutschen wird zudem der erste Buchstabe von Hauptwörtern groß geschrieben. Der Lesefluß erfolgt in beiden Sprachen zeilenweise von links nach rechts und innerhalb eines längeren Textes von oben nach unten.
Die Bedeutung des ersten Buchstabens wird im Werksatz besonders betont. Beim Setzen des Anfangsbuchstabens von Kapiteln und Abschnitten als Initiale wird das erste Zeichen oft als reich verziertes und sorgfältig gestaltetes Versal gesetzt. Anstelle von vollständig in Versalien gesetzten Wörtern kommen aufgrund der besseren Lesbarkeit Kapitälchen zum Einsatz. Dabei werden die Kleinbuchstaben des Wortes durch Versalien ersetzt, die in ihrer Größe der x-Höhe der jeweiligen Schriftart angepaßt sein können. Im englischen Werksatz werden in Überschriften, im Gegensatz zum Fließtext, Wörter wie Haupt- und Zeitwörter oder überhaupt alle Wörter mit einem Versal eingeleitet, um das Schriftbild ausgeglichener erscheinen zu lassen. So kann der Titel des Werks The legend of good women von Geoffrey Chaucer als The Legend of Good Women gedruckt werden.
Bei der Camel-Case-Konvention wird der erste Buchstabe eines Bezeichners grundsätzlich klein geschrieben, selbst dann, wenn innerhalb des Bezeichners Großbuchstaben vorkommen. Dadurch wird jenes Zeichen, das von hoher Bedeutung für das Erkennen eines Bezeichners ist, seiner Funktion beraubt und diese an den nächsten Großbuchstaben im Bezeichner übertragen. Ästhetisch unansprechender und schwer erfaßbarer Text ist die Folge; der Lesefluß wird durch die Unausgeglichenheit des Schriftbildes gestört.
Wahrnehmung und Erkennung von Wörtern
Beim Erkennen gedruckter Wörter durch den Menschen spielt neben anderen Kriterien deren Gestalt eine wichtige Rolle. Schreibfehler, welche die Gestalt eines Wortes verändern, erschweren es dem Betrachter, das Wort zu erkennen. Die Wahrscheinlichkeit des Erkennens eines falschen Wortes steigt dadurch. Die Gestalt eines Wortes kann auf verschiedenem Wege bestimmt werden. Eine Möglichkeit besteht darin, rechteckige Umrisse der einzelnen das Wort konstituierenden Zeichen heranzuziehen, eine andere liegt im Bestimmen eines genaueren Umrisses des gesamten Wortes. In dieser Arbeit soll zur grafischen Veranschaulichung die erste der beiden vorgestellten Methoden benutzt werden. Dies ist ausreichend, da zur Darstellung von Quellcode meist dicktengleiche Schriftarten zum Einsatz gelangen, in denen Zeichen einen gut durch ein Rechteck beschreibbaren Umriß besitzen.
Gemäß der zuvor angeführten Konventionen zur Benennung privater Variablen in .NET-Programmiersprachen würde der Wert der Eigenschaft UserName
in einer privaten Variablen mit Namen userName
, _UserName
, _userName
, m_UserName
oder m_userName
gespeichert werden. Durch die Kleinschreibung des ersten Zeichens im Bezeichner ändert sich auch dessen Gestalt. Anstelle des »U« sticht das »N« prominent als erstes Zeichen mit Oberlänge hervor, das Erkennen der Zusammengehörigkeit von Eigenschaft und Variable wird damit erschwert. Die folgende Tabelle gibt eine Übersicht über mehrere mögliche Benennungen der zur Eigenschaft UserName
gehörigen privaten Variablen.
Bezeichner | Gestalt | Konsistente Gestalt | Bedeutung |
---|---|---|---|
UserName |
— | Eigenschaft | |
userName |
Nein | Private Variable | |
_UserName |
Ja | Private Variable | |
_userName |
Nein | Private Variable | |
m_UserName |
Ja | Private Variable | |
m_userName |
Nein | Private Variable |
Wie der Übersicht entnommen werden kann, ändert das Voranstellen eines Präfixes die Gestalt eines Bezeichners nur unwesentlich, da der Präfix bei entsprechender Trennung, etwa durch einen Unterstrich, als klar von der ursprünglichen Gestalt abgesetzt wahrgenommen wird. Dieser Trennungseffekt wird verstärkt, wenn die Zeichen im Präfix keine Oberlängen aufweisen. Ein geschickt gewählter Präfix reichert den Bezeichner um Information zum Gültigkeitsbereich an, behält aber eine konsistente Gestalt bei, um eine Fehlerkennung zu vermeiden.
Die Camel-Case-Konvention als Fehlerquelle
Ein beim Schreiben von Code häufig auftretender Fehler ist die fälschliche Kleinschreibung des ersten Buchstabens eines Wortes. Eingabehilfen wie IntelliSense und eine automatische Eingabeprüfung können nur in begrenztem Umfang dazu beitragen, derartige Fehler zu verhindern und als Fehlerquelle zu entschärfen. So kann bei zwei gleichlautenden Bezeichnern, die sich lediglich in Groß- und Kleinschreibung eines einzigen Zeichens unterscheiden, nur aus dem semantischen Kontext ihrer Verwendung geschlossen werden, welcher der beiden Bezeichner gemeint ist. Diese Aufgabe kann daher nicht an den Computer übertragen werden. So ist es nicht einmal möglich, den Entwickler gezielt durch eine Compilerwarnung auf einen derartigen Eingabefehler hinzuweisen.
Folgendes Listing zeigt den C#-Quellcode einer Klasse mit einer Eigenschaft Foo
und einer privaten Variablen foo
. Beim Zuweisen eines Wertes an die Eigenschaft Foo
wird dieser auf seine Gültigkeit geprüft und eine Ausnahme geworfen, wenn der übergebene Wert nicht bestimmten Anforderungen genügt. In der mit dem Rufzeichen markierten Zeile hat der Entwickler versehentlich foo
statt Foo
eingegeben und damit die Validierung des zugewiesenen Wertes umgangen. Der Compiler kann den Fehler nicht entdecken, selbst dann nicht, wenn anstelle von foo
das qualifizierte this.foo
geschrieben worden wäre.
public class Test
{
private int foo;
public int Foo
{
get
{
return foo;
}
set
{
if (value < 10)
throw
new ArgumentException(
"Der Eigenschaftswert muß größergleich 9 sein."
)
;
foo = value;
}
}
public void SampleMethod()
{
Bla b = new Bla()
int i = b.GetNumber()
foo = i; // !
⋮
}
}
Folgendes Listing zeigt ein Codebeispiel, in dem ein Benutzer anhand einer übergebenen Identifikationsnummer gefunden und gelöscht werden soll, sofern es sich dabei nicht um einen bestimmten Testnutzer handelt. In der mit dem Rufzeichen markierten Zeile wollte der Entwickler den anhand der Identifikationsnummer gefundenen Benutzers mit jenem, der in der Eigenschaft TestUser
gespeichert ist, vergleichen. Irrtümlich hat der Entwickler jedoch testUser
anstelle von TestUser
eingegeben. Der Code ist zwar kompilierbar, aber er verhält sich anders, als vom Entwickler vorgesehen, da anstatt der Eigenschaft TestUser
der Wert der lokalen Variablen testUser
mit sich selbst verglichen wird.
public class Test
{
private User testUser;
public User TestUser
{
get { … }
set { … }
}
public void DeleteTestUserByID(int id)
{
User testUser = Management.GetTestUserByID(id);
⋮
if (testUser != testUser) // !
Management.DeleteUser(testUser);
}
}
Schlußwort
Aktuell eingesetzte Benennungskonventionen erwecken den Anschein, mehr festgeschriebene Abbilder althergebrachter und teils kruder Gewohnheiten von Entwicklern zu sein, als Ergebnisse einer wissenschaftlichen Auseinandersetzung. Dabei bietet es sich an, die Empfehlung der Konventionen argumentativ durch Hinzuziehung von Linguisten, Typographen, Wahrnehmungsforschern und Informatikern zu unterstützen.
Viele bestehende Konventionen reihen sie sich nahtlos in das Bild populärer Programmiersprachen ein, deren Syntax für eine einfache und schnelle Verarbeitung durch den Compiler, weniger aber eine einfache und sichere Codierung durch den Entwickler optimiert ist. Unter dem Gesichtspunkt der Benutzbarkeit geschaffene Programmiersprachen und Konventionen hätten das Potential, die Erlernbarkeit zu erleichtern und die Produktivität zu steigern.