Gute Namen für Klassen, Methoden und Variablen

Häufig enden kleine Besprechungen oder Diskussionen darüber, wie etwas umgesetzt wird, mit der Frage: “Ok und wie nennen wir die Klasse”? Ich antworte dann in der Regel: “Das ist die größte Herausforderung eines jeden Softwareentwicklers: gute Namen zu finden”. Oder wie Phil Karton sagte: “There are only two hard things in Computer Science: cache invalidation and naming things.

Hintergrund

Die Festlegung des Names, gerade bei Klassen, wird oft als Nebensache abgetan, die schnell erledigt werden sollte. Der Fokus wird immer auf die Planung der Klasse und ihrer Aufgabe gelegt, dabei gehört beides zusammen. Der Name einer Klasse beschreibt auch immer, was ihre Aufgabe ist. Kent Beck beschreibt in TDD im Kapitel “Metaphor”, wie das Festlegen des Namens im TDD-Ablauf weitere Architektur-Entscheidungen bestimmt. Je nachdem, welcher Name gewählt wird, trifft man im weiteren Ablauf unterschiedliche Entscheidungen, weil weitere Funktionalität zum Namen passt oder nicht. Der Name (oder hier die Metapher), der gewählt wird, lässt zum Teil auch unterschiedliche Implementierungsansätze entstehen.

Aber auch ohne TDD-Ansatz wird sich eine Klasse, je nachdem welchen Namen ich wähle, unterschiedlich weiterentwickeln. Ist der Name zu weit gefasst, wird in Zukunft eventuell Funktionalität hinzugefügt, die der ursprüngliche Entwickler gar nicht vorgesehen hatte.

Wieso sind gute Namen noch wichtig?

Vom Zusammenhang zwischen Architekturentscheidungen und Klassennamen abgesehen spricht ein großer, wichtiger Grund für gute Namen von Klassen, Variablen und Methoden: die Lesbarkeit. Wir Entwickler sind alle gleichzeitig Autoren und Leser und vergessen doch noch immer viel zu oft, dass unser Quellcode auch von anderen Lesern (a.k.a. Entwicklern) gelesen wird. Der Clean-Code-Ansatz, Quellcode als menschenlesbaren Text anzusehen, erzwingt genau das: gute Namen.

Finde ich im Code stellen wie $tmp->greaterThan($var2) weiß ich nicht, was der Autor mir damit sagen will. Eventuell hat er einen Kommentar hinterlassen, jedoch  reißt mich das Lesen des Kommentars aus dem eigentlichen Text (dem Quellcode) genauso heraus, wie eine Fußnote in einem Buch. 

Verwende ich aber gute Namen für die beiden Variablen und die Methode, könnte es so aussehen: $taskDeadline->exceeds($today). Ich weiß dann ganz genau,  was der Autor hier sagen möchte.

Neben den klar benannten Variablen hat in diesem kleinen Beispiel auch die Methode einen Namen erhalten, der nicht rein technisch beschreibt, was sie macht (sie prüft auf “größer”),  sondern einen Bezug zur Anwendung herstellt. Sie prüft, ob ein Datum ein anderes überschreitet – in Bezug auf die Lesbarkeit deutlich klarer als das eher technische “greaterThan”.

Ist die Namenswahl dann nicht ganz einfach?

Es klingt nun so, als ob man sich also nur auf gute Namen einigen muss und alles ist gut. Der Haken an der Sache: Das mit den guten Namen ist oft gar nicht so einfach

Alleine Clean Code gibt schon einige Regeln vor, die man einhalten sollte:

  • use meaningful distinctions
  • no noise words
  • use pronounceable names
  • use searchable names
  • avoid mental mapping
  • pick one word per concept
  • Solution Domain Names / Problem Domain Names beachten

Falls jemand nicht weiß, was sich hinter einem oder mehreren der Punkte verbirgt: Robert C. Martin – Clean Code lesen!

In vielen Fällen findet man anhand solcher Regeln tatsächlich sehr schnell einen Namen, der konkret beschreibt, was eine Klasse oder Methode tut bzw. was eine Variable enthält. Interessanter finde ich die Fälle, in denen das nicht so einfach ist.

Schauen wir uns zwei Beispiele an

Das erste Beispiel:

Wir haben eine Methode “compare”, die zwei Datumswerte vergleicht und ermittelt, ob das erste Datum zeitlich vor dem zweiten Datum liegt.

private function compare($a, $b)
{
  $startTimeA = $a->getStartTime();
  $startTimeB = $b->getStartTime();

  return $startTimeA < startTimeB;
}

$a, $b, $startDateA und $startDateB sind keine gut zu unterscheidenden Namen (meaningful distinctions) und in Diskussionen auch nicht gut aussprechbar (pronounceable names). Wie aber benenne ich zwei abstrakte Datumswerte, die ich miteinander vergleiche, ohne etwas über die beiden zu wissen? An der Stelle sollte man sich immer die Frage stellen: Weiß ich wirklich gar nichts über die Werte? Die einzig erkennbare Information versteckt sich im return-Statement. Es wird “true” zurückgegeben, wenn $startDateA kleiner ist als $startDateB. Die Methode nimmt also an, dass $startDateA (und damit $a) vor $startDateB (und $b) liegt (-> true-Fall). 

Aufgrund dieser einen verfügbaren Information könnte ich folgende Namen wählen:

private function compare($precedingEvent, $subsequentEvent)
{
  $precedingStartTime = $precedingEvent->getStartTime();
  $subsequentStartTime = $subsequentEvent->getStartTime();

  return $precedingStartTime < $subsequentStartTime;
}

Jetzt habe ich klar unterscheidbare Namen und muss auch in Diskussionen nicht mehr überlegen, was A und was B ist, da ich die Annahme des return-Statements in Variablennamen verpackt habe.

Der Name der Methode - compare - ist ein weiteres Beispiel. Die Methode wird in der entsprechenden Klasse verwendet, um eine Liste von Terminen an einem Tag zeitlich zu sortieren. “compare” lässt schon darauf schließen, dass ein boolescher Wert zurückgegeben wird, mehr aber nicht. Um auch hier die Annahme des return-Statements deutlich zu machen, wäre z. B. isInCorrectOrder ein guter Name.

Das zweite Beispiel:

foreach ($this->flatten($data) as $variable)
{
   $pairs []= $variable['name'].'='.$variable['value'];
}

In dem kleinen Code-Block verstecken sich (fast) nur “noise-words”: variable, data, pairs. Natürlich enthält die Variable $data Daten und natürlich ist $variable eine Variable. Schaut man sich die Code-Stelle genauer an, kommt folgende Erkenntnis: $data enthält alle URL-Parameter eines GET-Requests und $variable ist einer dieser Parameter (im Sprachgebrauch häufig als GET-Variable bezeichnet). Die reinen “noise-words” haben also schon einen Bezug zum Inhalt. Er ist nur dadurch schwer zu erkennen, da es noise-words sind und aus HTTP-Sicht fachlich die falschen Begriffe verwendet wurden.

Eine Variante wäre also:

foreach ($this->flatten($getData) as $getVariable)
{
   $pairs []= $getVariable['name'].'='.$getVariable['value'];
}

Zufrieden wäre ich damit noch immer nicht. Als neuer Leser würde ich trotzdem an den “noise-words” hängen bleiben und fachlich sind es noch immer die falschen Begriffe.

Jetzt könnte man das “variable” weglassen und die Variable nur $get nennen. Mit dem Namen wäre ich aber auch noch nicht zufrieden, da er zu weit gefasst ist. Auch für $pairs muss noch ein besserer Name gefunden werden.

Die bessere Variante:

foreach ($this->flatten($httpGetQuery) as $httpGetQueryPart)
{
  $httpGetQueryStrings []= 
  $httpGetQueryPart['name'].'='.$httpGetQueryPart['value'];
}

Durch $httpGetQuery habe ich klar benannt, dass es sich um Werte aus einer Query eines HTTP-GET-Requests handelt. Die drei verschiedenen Variablen zu unterscheiden ist die noch größere Herausforderung.

Sprache

Neben der Namenswahl in Form des richtigen Begriffes ist natürlich auch die Sprache wichtig. Dazu gehört nicht nur die Frage, wann Begriffe in Englisch und wann in Deutsch verwendet werden. Aber auch die fachspezifische Sprache ist wichtig. In Clean Code wird explizit dazu aufgerufen “solution domain names” und “problem domain names” zu verwenden. 

Ein Entwickler sollte immer davon ausgehen, dass seine Leser Entwickler sind (→ Begriffe aus dem Bereich Softwareentwicklung / IT können vorausgesetzt werden) und sich auch in der Firmendomäne auskennt (→ in unserem Fall: Fachbegriffe aus der Immobilienbranche sind ok). Hier kann es natürlich zu Konflikten kommen.

Konflikte dank unterschiedlicher Bedeutungen eines Begriffes

Nehmen wir ein Beispiel aus der Finanzbranche. Eine Transaktion bedeutet für eine Softwareentwicklerin etwas anderes als für einen Bankangestellten. Die Entwicklerin muss sich also in der Firmendomäne auskennen, um das erkennen zu können. Andererseits ist hier zu erkennen: Gut funktionierende Namen brauchen einen guten Kontext. Lese ich ein Fachbuch über Softwareentwicklung und lese darin etwas über Transaktionen ist mir klar, dass es um etwas anderes geht als bei der Transaktion im Artikel über den letzten Finanzskandal. Genau so muss auch beim Lesen von Quellcode klar ersichtlich sein, in welchem Kontext (oder auf welcher Abstraktionsebene) sich eine Klasse befindet. Und wieder haben wir einen sehr direkten Zusammenhang zwischen Namen und Architektur.

Einheitliche Absprachen

Um zurück zur Landessprache zu kommen: Wir haben bei uns die Regel, dass Fachbegriffe aus der Immobilienbranche in deutscher Sprache verwendet werden dürfen. So weit es geht, würde ich darauf immer verzichten. Auch der Sprachwechsel ist ein Bruch beim Lesen. Es gibt zum Teil doppeldeutige Wörter (deutsch: Tag / englisch: tag → Variablennamen werden in der Regel klein geschrieben und schon ist unklar, was gemeint ist).

Fazit

Egal, ob es um die richtige Übersetzung, den richtigen Fachbegriff oder ganz allgemein um die Wahl des richtigen Namens für eine Variable, Methode oder Klasse geht: Im Zweifelsfall sollte man im Team diskutieren, so wie man es auch bei anderen Architektur-Entscheidungen tut. Diese Diskussionen, aber auch Recherchen in RFCs oder Fachliteratur sind gut investierte Zeit, da gute Namen den Code verständlicher machen. Andere Entwickler – oder man selbst zu späterer Zeit – können den Code besser lesen und man spart Zeit und Nerven. Dazu sind Diskussionen über die Namen auch immer wertvoll, um Wissen auszutauschen: Wissen über fachliche Themen und Wissen für die Firmendomäne.

Quellen

  • Robert C. Martin – Clean Code
  • Kent Beck – Test-Driven Development by Example

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.