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:

Methods should be verbs, in mixed case with the first letter lowercase, with the first letter of each internal word capitalized.

Except for variables, all instance, class, and class constants are in mixed case with a lowercase first letter. Internal words start with capital letters. Variable names should not start with underscore “_” or dollar sign “$” characters, even though both are allowed.

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:

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:

  • Spell out all words used in a field name. Use abbreviations only if developers generally understand them. Do not use uppercase letters for field names. The following is an example of correctly named fields.

    [Visual Basic]
    Class SampleClass
       Private url As String
       Private destinationUrl As String
    End Class
    
    [C#]
    class SampleClass 
    {
       string url;
       string destinationUrl;
    }
  • Do not use Hungarian notation for field names. Good names describe semantics, not type.

  • Do not apply a prefix to field names or static field names. Specifically, do not apply a prefix to a field name to distinguish between static and nonstatic fields. For example, applying a g_ or s_ prefix is incorrect.

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.

[Foto] St.-Florians-Psalter mit Kapitel- und Absatzinitialen

St.-Florians-Psalter mit Kapitel- und Absatzinitialen. (Bildquelle)

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.

Übersicht der Benennungsmöglichkeiten der zur Eigenschaft UserName gehörigen privaten Variablen
Bezeichner Gestalt Konsistente Gestalt Bedeutung
UserName [Illustration] Gestalt des Bezeichners 'UserName' Eigenschaft
userName [Illustration] Gestalt des Bezeichners 'userName' Nein Private Variable
_UserName [Illustration] Gestalt des Bezeichners '_UserName' Ja Private Variable
_userName [Illustration] Gestalt des Bezeichners '_userName' Nein Private Variable
m_UserName [Illustration] Gestalt des Bezeichners 'm_UserName' Ja Private Variable
m_userName [Illustration] Gestalt des Bezeichners '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.