Einheitliche Namensgebung
Einleitung
Das zweit-schwierigste Problem in der IT ist die Kunden zu verstehen, was sie haben wollen. Das schwierigste Problem ist, gute Namen zu finden.
Allen Kapiteln wurde eine eindeutige Nummerierung, der Richtliniennummer, hinzugefügt, um eine eindeutige Identifikation zu ermöglichen. Jede Richtliniennummer besteht aus dem Buchstaben GN(General Naming) gefolgt von einer Nummer, die den Abschnitt identifiziert. Damit kann eine Regel eindeutig identifiziert werden, z.B. für ein Code-Review.
GN1 Konventionen durch eingesetzte Sprache
Unterschiede in der Namensgebung bei verschiedenen Programmiersprachen
Die Namensgebung in der Softwareentwicklung ist von der verwendeten Programmiersprache abhängig.
Es soll von den hier vorgegebenen Regeln abgewichen werden, wenn die Sprache spezifische Konventionen vorgibt.
GN2 Allgemeine Regeln
- Verwende die Sprache der Domäne, in der die Software entwickelt wird.
- Verwende Namen, die auch für das Geschäftsmodell oder die Domäne verständlich sind.
- Vermeide das ersetzen von Domänenspezifischen Namen durch technische Namen (
Item
stattArticle
oder sogarInvoice
). Andernfalls müssen Entwickler ständig zwischen der Domäne und der technischen Sprache wechseln.
- Je globaler eine Variable ist (Funktion, Klasse, statische Klasse, global), desto besser sollte der Name gewählt sein.
- Prüfe, ob der Name korrekt geschrieben ist (z.B.
Asterisk
stattAsterix
,Exception
stattExeption
,Initialize
stattInitialise
). - Verwende so kurze und präzise Namen wie möglich, aber so lang wie nötig.
- Verwende die gleichen Wörter für die gleichen Konzepte in der gesamten Codebasis (Konsistenz, z.B.
Account
stattUser
). - Vermeide Abkürzungen, die nicht allgemein bekannt sind (z.B.
load
stattld
). - Vermeide Zahlen in Namen, wenn sie nicht Teil des Namens sind (z.B.
user1
stattuser
). - Vermeide komplizierte oder nicht gebräuchliche Wörter (z.B.
abracadabra
stattmagic
). - Vermeide Überraschungen in Namen, weil der Name nicht das beschreibt, was der Wert enthält oder die Methode tut (Least astonishment)
- Übertreibe es nicht mit der Wortwahl, bleibe einfach und verständlich (
release
stattrelinquish
odergiveUp
).
Beispiele:
calculateTotalAmountOfItems
soll den Gesamtbetrag der Artikel berechnen und nicht z.B. die Differenz (Least astonishment)- Keine Methode soll eine Datei löschen, wenn sie
calculateTotalAmountOfItems
heißt (Least astonishment). - Werte im Objekt dürfen nicht verändert werden, wenn die Methode
getFullName
heißt (Least astonishment). - globale Variablen sollen nicht verändert werden, wenn die Methode printDocument heißt (Seiteneffekte).
- Eine Methode, die
getFullName
heißt, soll keine FileNotFoundException werfen. - Eine Methode, die
calculateTotalAmountOfItems
heißt, soll keine NullPointerException werfen (Fehler in der Methode). - Eine Methode, die printDocument heißt, soll keine
NetworkException
werfen (Domänen-fremd)
GN3 Unspezifische Namen
Unspezifische Namen sind zu vermeiden, die so generisch sind, dass sie keine Information über den Typ oder den Wert enthalten.
Beispiele sind: temp
, value
, values
, items
, data
, object
, stuff
, things
, element
, entity
, item
, object
, instance
oder das berüchtigte foo
, foobar
, baz
.
Bessere Namen sind z.B.: tempDirectoryPath
, totalAmount
, itemListOfArticles
, userCustomData
, elementFindInUserList
, entityUser
, itemArticle
, instanceOfUser
.
Abwägung
Unspezifische Namen können in bestimmten Situationen verwendet werden, wenn der Kontext klar ist.
GN4 Schreibweise
Die Schreibweise von Variablen, Methoden, Konstanten, Typen und Klassen soll konsistent sein und den Konventionen der Sprache folgen.
Die Schreibweise wird detailliert im Kapitel der entsprechenden Sprache beschrieben.
Groß- und Kleinschreibung der Namen
Die hier verwendeten Beispiele sind in der Regel in camelCase geschrieben, aber die Schreibweise kann je nach Sprache variieren.
GN5 Präfixe und Suffixe
Vermeide Präfixe und Suffixe, wenn der Kontext bereits klar ist.
Beispiele:
name
stattstrName
, wenn der Typ klar ist.age
stattintAge
Name
stattNameType
User::name()
stattUser::setUserName()
, wenn der Kontext Benutzer klar ist.com.company.ClassName
stattcom.company.CompanyClassName
, wenn der Namespace die Trennung klar macht.
Sollen Präfixe oder Suffixe notwendig sein, sollen eine Aufteilung in Betracht gezogen werden nach dem Prinzip Separation of Concerns.
Achtung
Nicht alle Sprachen können ohne getter und setter auskommen, daher kann es notwendig sein, diese Präfixe zu verwenden.
GN6 Variablen
- Variablen sollen mit einem Nomen benannt werden, das den Wert beschreibt
name
,surname
,firstName
,fullName
. - Wenn der Kontext nicht klar ist, soll das Nomen genauer beschrieben werden
textOfArticle
,messageOfStatus
. - Die Groß- und Kleinschreibung soll konsistent sein und den Konventionen der Sprache folgen.
GN7 mögliche Nullwerte in Variablen
Variablen, die möglicherweise null
sind, können auf folgende Arten markiert werden:
const nullableName = null;
const nameOrNull = null;
const nameOrUndefined = undefined;
const nameOrEmpty = '';
const nameOrNothing = '';
const nameOrNone = '';
String nullableName = null;
String nameOrNull = null;
String nameOrEmpty = "";
String nameOrNothing = "";
String nameOrNone = "";
let nullableName: string | null = null;
let nameOrNull: string | null = null;
let nameOrEmpty: string = "";
let nameOrNothing: string = "";
let nameOrNone: string = "";
string? nullableName = null;
string? nameOrNull = null;
string nameOrEmpty = "";
string nameOrNothing = "";
Unterschiede in den Sprachen
Wie die Variable annotiert wird, hängt von der verwendeten Programmiersprache ab. Es muss darauf geachtet werden, dass die Annotationen dem Konzept von null
oder undefinierten Werten entsprechen.
Optional
In manchen Sprachen gibt es spezielle Typen, die null
oder undefinierte Werte erlauben. Diese Typen sollen stattdessen verwendet werden, um die Absicht klar zu machen.
Verwende Optional
in Java, Nullable
in C#, oder Custom-Optional in JS/TS um die Absicht klar zu machen.
GN8 Namen für die Anzahl von Elementen
Variablen sollten einen Prä- oder Suffix haben, wie numberOf<Thing>
oder <Thing>Count
, wie in numberOfCars
oder carCount
.
GN9 Schleifenvariablen
- Variablen von Schleifenvariablen können mit
i
,j
,k
,l
,m
benannt werden, wenn sie als reiner Index ohne Bedeutung verwendet werden.i
oderj
darf nicht zusammen mitl
verwendet werden, da es leicht zu Verwechslungen führen kann.- Es dürfen nur bis zu
2
dieser Schleifenvariablennamen verwendet werden, um die Lesbarkeit zu erhöhen, andernfalls sollen sprechende Namen verwendet werden.
- Koordinaten in Schleifen sollen mit
x
,y
,z
benannt werden und mit einer Zahl, falls mehrere Koordinaten verwendet werdenx1
,y1
,z1
(die Berechnung von Matrizen oder Vektoren macht dies oft notwendig). - Schleifenvariablen sollen mit einem Nomen benannt werden, das den Wert beschreibt, wenn sie eine Bedeutung haben
index
,counter
,position
.
GN10 Ganzzahlen
- Variablen von Ganzzahlen sollen mit einem Nomen benannt werden, das den Wert beschreibt
ageInYears
,weightInKg
,heightInCm
.- andere Variablen sollen mit einem Nomen benannt werden, das den Wert beschreibt
indexOfUser
,counterOfUsers
.
- andere Variablen sollen mit einem Nomen benannt werden, das den Wert beschreibt
- Allgemeine Nomen sollen mit einem weitere Nomen benannt werden, das den Wert beschreibt
amountOfItems
,numberOfUsers
odertextOfArticle
. - Gewichte, Zeiten, Größe, Entfernungen, Geschwindigkeiten, Währungen, Namen sollen mit einem Nomen benannt werden, das den Wert beschreibt
weightInKg
,timeInSeconds
,sizeInBytes
,distanceInKm
,speedInKmPerHour
,valueInDollars
,valueInEuros
oderamountInCents
. value
soll vermieden werden, da es keine Information über den Typ enthält und der Kontext nicht klar ist (z.B. zu großer Abstand zwischen Deklaration und Verwendung). Stattvalue
soll der Typname verwendet werden, wenn der Typ nicht offensichtlich istvalueInDollars
,valueInEuros
.- Währung soll in der Regel in der kleinsten Einheit gespeichert werden, z.B. in Cents statt in Euro (101c statt 1,01€ als Fließkommazahl).
Sekunden vs. Millisekunden Fehlerquelle
Eine häufige Fehlerquelle ist, dass Zeiten in Sekunden oder Millisekunden gespeichert werden, aber nicht klar ist, welcher Typ verwendet wird. Dies führt oft dazu, dass ein Wert in Sekunden definiert ist, aber ein Wert in Millisekunden zugewiesen wird, so dass der Wert dann das Tausendfache des erwarteten Wertes ist. Die Folge ist, dass beispielsweise eine Verzögerung von 1000 Millisekunden (1 Sekunde) als 1000 Sekunden (16 Minuten) interpretiert wird, was zu langen Wartezeiten führt.
GN11 Fließkommazahlen
- Variablen von Fließkommazahlen sollen mit einem Nomen benannt werden, das den Wert beschreibt
weightInKg
,energyInJoules
,speedInKmPerHour
. - Währungen dürfen nicht in Fließkommazahlen gespeichert werden, da dies zu Rundungsfehlern führen kann (0.1 + 0.2 = 0.30000000000000004).
Beispiele
GN11 Positiv
- rainFallAmount
- rainFallAmountInMillimeters
- widthInCentimeters
- angleInDegrees
- energyConsumptionInKilowattHours
- waterUsageAmountInLiters
- oxygenLevelAmountInPercent
- stressLevelAmountInCortisolUnits
- pollutionAmountInPartsPerMillion
- verticalSpeedAmountInMetersPerSecond
- accelerationAmountInMetersPerSecondSquared
GN11 Negativ
- rainFall
- width
- angle
- money
- degree
- energy
- waterUsage
- oxygenLevel
- stressLevel
- pollution
- verticalSpeed
GN12 Boolean
- Werte für Boolean sollen mit einem Präfix
is
,has
,can
,should
oderwill
gefolgt von einem Adjektiv benannt werden. Die Vergangenheitsformen der Präfixe können auch verwendet werden, wenn der Kontext dies erfordertwas
,did
,had
. does
soll vermieden werden, da es durch die anderen Präfixe besser ersetzt werden kann. Wörter wieexists
können jedoch verwendet, daisExists
grammatikalisch falsch ist.empty
soll vermieden werden, da es auch ein Verb handeln kann für eine Methodeempty()
.- weitere Präfixe wie
allows
,contains
,supports
,enables
,disables
,blocks
,accepts
,rejects
,requires
,forbids
,denies
,grants
,revokes
,permits
,prohibits
können verwendet werden, wenn sie besser zum Kontext passen. - Es gibt Sprachen, die Eigenschaften zum Lesen und Setzen als einzelnen Aufruf zulassen (z.B.
x = enabled()
undenabled(true)
). In diesem Fall kann der Präfix wegfallen, es sonst zu einer Verwirrung mit der set-Methode führen würde (isEnabled(true)
).
Beispiele
GN12 Positiv
- isEnabled
- hasChildren
- canPlay
- shouldClose
- containsText
- wasFound
- willBeShown
- doesExist
- didSucceed
- allowsMultiple
GN12 Negativ
- enabled
- children
- played
- closed
- found
GN13 Strings
- Variablen von Strings sollen mit einem Nomen benannt werden, das den Wert beschreibt
name
,surname
,firstName
,fullName
- Der Inhalt kann auch mit
as
beschrieben werden, wenn der Kontext nicht klar istyearAsString
,statusAsString
. - Wenn der Kontext nicht klar ist, soll das Nomen genauer beschrieben werden
textOfArticle
,messageOfStatus
.
GN14 Listen, Sets
- Variablen von Listen sollen mit einem Nomen im Plural benannt werden, das den Inhalt beschreibt
users
,shoppingItems
,articles
. - Alternativ können Präfixe wie
list
,array
,collection
oderset
verwendet werden, wenn der Kontext nicht klar istlistOfUsers
,arrayOfArticles
,collectionOfItems
,setOfItems
.
GN15 Maps, Dictionary
Variablen von Maps und Dictionaries sollen mit dem Muster keyToValue
benannt werden, das den Inhalt beschreibt userIdToUser
, articleIdToArticle
für Map<Integer, User>
, Map<Integer, Article>
.
GN16 Tuple
Eine Variable für ein Tuple soll mit dem Muster firstValueAndSecondValue
benannt werden, das den Inhalt beschreibt xAndY
, latitudeAndLongitude
, startAndEnd
oder beginAndEnd
.
GN17 Optional
Eine Variablen von Optional
oder Nullable
kann mit dem Muster maybeValue
oder valueOrNull
benannt werden, das den Inhalt beschreibt maybeUser
, valueOrNull
, userOrNull
.
Optional/Nullable vs. null
Diese Regel ist optional, da der Typ der Variable klar macht, dass es sich hierbei um einen Optional
oder Nullable
Wert handelt.
Compiler und Linter prüfen in der Regel, ob ein Zugriff vor einer Prüfung stattfindet und melden dies als Fehler.
GN18 Namensräume und Packages
Die Namen von Namensräumen und Packages sollen entsprechend der eingesetzten Sprache und den Konventionen benannt werden.
GN19 Klassen
Klassen präsentieren Dinge oder Akteure. Sie sollen daher konsistent benannt werden und mit einem Nomen enden (z.B.
Person
,Article
,User
).Abgeleitete Klassen sollen die Basisklasse oder das Basisinterface im Namen enthalten. Z.B. Klassen
User
und implementiertes InterfaceAccount
->UserAccount
oder die KlassenShape
undCircle
->CircleShape
. Dies gilt nicht für Interfaces, die zusätzliche Funktionalität bereitstellen (Serializable
,Comparable
,Validatable
).Klassen, die ein Interface implementieren, sollen mit
Impl
enden (z.B.UserImpl
,ArticleImpl
). Von dieser Regel kann abgewichen werden, wenn die Klassen durch Namensräume oder Packages getrennt sind.Abstrakte Klassen sollen mit
Abstract
enden (z.B.PersonAbstract
,ArticleAbstract
,UserAbstract
).
GN20 Interfaces
Interfaces präsentieren Dinge, Akteure oder Fähigkeiten und sollen ähnlich wie Klassen benannt werden, jedoch mit einem abstrakten Nomen enden (z.B. Serializer
, Comparator
, Validator
). Interfaces, die eine Fähigkeit präsentieren, sollen mit einem Adjektiv enden (z.B. Serializable
, Comparable
, Validatable
).
Interfaces sollen nicht mit I
beginnen, da dies redundant ist und die Sprache bereits durch die Syntax klarstellt, dass es sich um ein Interface handelt. Ausnahmen sind Sprachen, die Interfaces mit Präfix als Konvention verwenden (z.B. I
in C#).
GN21 Funktionen und Methoden
- Funktionen und Methoden sollen mit einem Verb beginnen, das die Aktion beschreibt, die sie ausführen (
printDocument
,calculateTotalAmountOfItems
). - Der Name beginnt mit einem Verb und bezieht dabei auch die Parameter mit ein, sodass der Name die Funktionalität der Methode beschreibt.
- Parameter in den Funktionsnamen sind optional, wenn der Kontext klar ist oder zu viele Parameter den Namen unübersichtlich machen. (statt
sumOfXYZ(int x, int y, int z)
sollsum
oder bessersumCoordinates
, wenn es sich um 3D-Koordinate handelt, verwendet werden).
- Parameter in den Funktionsnamen sind optional, wenn der Kontext klar ist oder zu viele Parameter den Namen unübersichtlich machen. (statt
- Namen können lang sein, solange sie die Funktionalität klar beschreiben (z.B.
calculateTotalAmountOfItems
). - Weiterhin kann das Verb ausgeschmückt werden, um die Aktion genauer zu beschreiben (
compareTextCaseInsensitive
).
Beachte jedoch auch:
- Methoden-/Funktionsnamen sollen nur eine Aktion konkret beschreiben
DoSomethingAndSomethingElse
ist ein Hinweis auf eine zu komplexe Methode. - Methoden-/Funktionsnamen sollen nur alphanumerische Zeichen enthalten (Buchstaben, Zahlen, Unterstriche).
- Methoden-/Funktionsnamen sollen nicht mehr als
25
Zeichen lang sein. In diesem Fall soll die Methode in kleinere Methoden aufgeteilt werden (siehe Single Responsibility Principle). - Die Namen können Typen (z.B.
String
) enthalten, wenn die Sprache nicht typisiert ist (JavaScript) und der Typ nicht offensichtlich ist (serializeJsonObject
). - Methoden sollen anhand ihrer Funktionalität benannt werden, nicht anhand ihrer Implementierung.
Beispiele:
serialize(json : JsonObject), aber serializeJsonObject(json)
deserialize(json : String)
validate(data : any)
compare(a : Integer, b : Integer) oder compareIntegers(a, b)
compareTextCaseInsensitive(a, b) oder compareCaseInsensitive(a: String, b: String)
writeOnFlush() statt write(), wenn die Methode erst beim Flush schreibt
GN22 Funktionen- und Methodenparameter
Die Namen von Funktionen- und Methodenparametern sollen mit denen von Variablen übereinstimmen.
GN23 Methodenpaare
Methoden, die ein Paar bilden, sollen mit den gleichen Wörtern beginnen. Zum Beispiel:
- acquire/release
- add/remove
- begin/end
- create/destroy
- encode/decode
- encrypt/decrypt
- get/put
- increase/decrease
- increment/decrement
- initialize/finalize, terminate
- insert/delete
- join/detach
- launch/terminate
- load/save
- login/logout
- logon/logoff
- obtain/release
- open/close
- pause/resume
- publish/unpublish
- subscribe/unsubscribe
- read/write
- reserve/release
- start/finish
- start/stop/restart
- startup/shutdown
- store/retrieve, restore
- use/release
Namen können auch mit Präfixen versehen werden, um die Bedeutung zu verdeutlichen. Zum Beispiel:
<something> / un<something>
<something> / de<something>
<something> / dis<something>
Beispiele:
- assign/unassign
- connect/disconnect
- follow/unfollow
- install/uninstall
- serialize/deserialize
- subscribe/unsubscribe
Achtung
In den Beispielen sind einige Namen von Methodenpaare doppelt vorhanden. Es sollte im Quellcode nur eine Variante verwendet werden.
GN24 Methoden mit Boolean-Rückgabewerten
Methoden, die einen Boolean-Wert zurückgeben, sollen mit einem Präfix is
, has
, can
, should
oder will
gefolgt von einem Adjektiv beginnen.
Beispiele:
isReady()
hasChildren()
canEdit()
shouldDisplay()
willDestroy()
Der Präfix
does
soll vermieden werden, da er durch die anderen Präfixe besser ersetzt werden kann.
INFO
Spezifischere Präfixe wie contains
oder supports
sollen verwendet werden, wenn sie besser in den Kontext passen (z.B. in Listen oder Collections).
GN25 Getter und Setter
Getter sollen kein Präfix haben, Setter sollen durch Methoden ersetzt werden, die eine Aktion mit der Eigenschaft durchführen (Prinzip Tell, Don't Ask).
Die Silbe get
ist überflüssig, da sie keine zusätzliche Information hinzufügt (wie z.B. auch der Typname im Variablenname). Heutige Entwicklungsumgebungen bieten Code-Vervollständigung, sodass der Unterschied zwischen Getter und Setter offensichtlich ist. Stattdessen sollen Domain-spezifische Namen direkt verwendet werden
Beispiele:
`name()` statt `getName()`
Manche Programmiersprachen erfordern die Verwendung von
get
undset
für Getter und Setter.
Achtung
Wenn Klassen nur aus Getter und Setter bestehen, soll die Klasse neu bewertet werden, da sie gegen das Prinzip Information Hiding verstößt.
GN26 Build-Pattern Methoden
Methoden für das Build-Pattern sollen mit with
beginnen. Das Endstück
soll den Namen build
haben, denn der Kontext soll mit dem Namen der Klasse oder der Builder-Methode klar sein.
Beispiele:
PersonBuilder
.withName(name)
.withAge(age)
.withAddress(address)
.build()
Achtung
Das Prefix add
soll vermieden werden, da es zu Verwirrung führen kann, ob es sich um eine Methode zur Hinzufügung oder zum Setzen handelt.
GN27 Factory-Methode
Methoden für das Factory-Pattern sollen mit create
beginnen gefolgt von einem Nomen, das den Typ beschreibt. Z.B. createUser
, createArticle
, createProduct
. Präpositionen wie with
, for
, from
, of
können verwendet werden, die Art der Factory-Methode zu beschreiben createUserWithRole
, createArticleForUser
, createProductFromJson
.
GN28 Verwechslung von Verben und Adjektive
Verben UND Adjektive ohne die hier vorgestellten Präfixe können zu Verwechslungen führen. Einige dieser Worte im Englischen können durch ihre Schreibweise nicht unterschieden werden, ob sie ein Verb oder Adjektiv sind.
empty
kann ein Adjektiv (im SinneisEmpty
) oder ein Verb (to empty
) sein.free
kann ein Adjektiv (im SinneisFree
) oder ein Verb (to free
) sein.open
kann ein Adjektiv (im SinneisOpen
) oder ein Verb (to open
) sein.
GN29 Asynchrone Methoden
Methoden sollen anhand ihrer Funktionalität benannt werden, nicht anhand ihrer Implementierung.
loadUserDataAsync
,requestUserData
lädt die Benutzerdaten asynchronloadUserData
,sendUserData
lädt die Benutzerdaten synchron
GN30 Unbenutzte Namen in Variablen und Parameter
Es sollen keine unbenutzten Variablen und Parameter im Code vorhanden sein.
- Wenn die Funktionsdeklaration die Parameter vorschreibt, kann
_
als Platzhalter für unbenutzte Parameter verwendet werden. - Mehrere unbenutzte Parameter können durch
(_, __, ___)
etc. gekennzeichnet werden. - Ist der Einsatz von
_
nicht möglich, sollen die Parameter umbenannt werden, um zu verdeutlichen, dass sie nicht verwendet werden (unused
bzw.unusedName1
,unusedName2
).