Warum Konventionen so verdammt wichtig sind

Veröffentlicht: vor einem monat · Lesedauer ca. 20 Minuten

Heute möchte ich mal ein etwas anderen Post schreiben.

Wer mich ein wenig kennt, wird wissen, dass ich nicht so leicht aus der Ruhe zu bringen bin. Jedoch stoße ich in letzter Zeit immer mal wieder auf etwas, was mich wirklich etwas aufregt.

Die Rede ist von Code Conventions.

Dabei handelt es sich noch nicht einmal um gute oder schlechte Design Pattern, die Qualität oder Clean Code.

Es geht wirklich um so komplett banale Sachen wie das Setzen von einer Klammer, Groß- und Kleinschreibung von Methoden, Variablen oder sonst noch etwas.

Was ist eine Konvention

Ich finde, der Duden beschreibt das Wort sehr treffend.

1. Abkommen, [völkerrechtlicher] Vertrag.

2. Regel des Umgangs, des sozialen Verhaltens, die für die Gesellschaft als Verhaltensnorm gilt

3. Regel 

Auch die Synonyme sind ziemlich verständlich gewählt. Ich habe mal die wichtigsten hervorgehoben:

Anstand, Anstandsregel, Brauch, Etikette, gesellschaftliche Übereinkunft/Umgangsform, Kleiderordnung, Protokoll, Sitte, Usus, Verhaltenskodex, Verhaltens[maß]regel, Verhaltensnorm

Aber auch Wikipedia schreibt es sehr gut:

Eine Konvention (Aussprache: [kɔnvɛnˈʦi̯oːn]; vom lateinischen conventio für „Übereinkunft“ oder „Zusammenkunft“) ist eine (nicht notwendig festgeschriebene) Regel, die von einer Gruppe von Menschen aufgrund eines beschlossenen Konsenses eingehalten wird. Die Übereinkunft kann stillschweigend zustande gekommen oder ausgehandelt worden sein

Zusammengefasst bedeutet es, dass über die Zeit sich gewisse Standards durchgesetzt haben, die man als Entwickler auch beachtet werden sollten.

Warum werden die Standards nicht eingehalten?

Es gibt eigentlich genau 3 Gruppen von Programmierern, die sich an Konventionen nicht halten.

1.Anfänger

Bei Anfängern habe ich noch Verständnis für. Es kann schon ganz schön viel sein, sich die ganzen Regeln einzuprägen und auch noch anwenden.

Teilweise wissen die Anfänger es auch nicht besser, weil es ihnen einfach nicht (anders) gezeigt wurde oder sich mit dem ganzen Thema (noch) nicht beschäftigt haben.

2. „Polyglotte“

Gemeint sind Menschen, die verschiedene Programmiersprachen verwenden müssen. Der Klassiker wäre JavaScript und z. B. C#, PHP oder auch Java.

Hier kann es passieren, dass man sich über die Zeit ein Stil angeeignet hat und diesen „unbewusst“ in einer anderen Sprache anwendet.

Auf die Unterschiede gehe ich später noch genauer ein.

3. Ignorante

Und das sind die Leute, die es besser Wissen. Alle die gegen den Strom schwimmen. Die ganzen „Kevins“ dieser Welt. Alle, die es komplett absichtlich machen.

Und genau solche Leute gehen mir tierisch auf den Keks.

Dabei ist doch ziemlich einfach und bringt einen hohen Nutzen gegenüber einem geringen Aufwand.

Beim Lesen vom Quellcode weiß man schon was es ist und worum es sich handelt. Man muss nicht unnötig nachdenken und sich unnötig umdenken.

Warum ist das Einhalten einer Konvention so wichtig?

An dieser Stelle möchte ich mal ein kleines Beispiel bringen bei dem im Hohen maß eine Konvention, nein eigentlich sogar eine festgelegte Regel, verletzt wurde und dadurch fast tödlich endete.

Ich wurde einmal gebeten, eine Leuchte zu montieren. Ich bin zwar nicht der allerbeste Elektriker und verfüge auch nicht über eine 3-jährige Ausbildung in diesem Bereich, jedoch bin ich ein zertifizierter „Helfershelfer“ 🙂

Ausgangssituation war, dass zwei Leuchten in Reihe geschaltet waren und mit dem Lichtschalter nur eine Leuchte angeschaltet werden konnte. Die andere reagierte komischerweise nur, wenn ein Verbraucher in der Steckdose angeschlossen wurde.

Dies klang für mich schon ziemlich komisch.

Nachdem ich den Schalter aufgeschraubt und nur ein Kabel (NYM-J 3×1.5mm²) gesehen habe, habe ich mein Messgerät ausgepackt und alles mal kurzerhand durchgemessen.

Das erschreckende Ergebnis war, dass auf der blauen Leitung (Masse) permanent Spannung anlag und dem Schwarzen (Phase) geschaltet wurde. Grün/Gelb (Erdung) war an der Stelle nur Deko. „Geschaltet“ wurde hinter der Leuchte, sodass an der Fassung permanent Spannung anlag.

Parallel dazu führte ein Kabel zur Steckdose, die mit der zweiten Leuchte in Reihe geschaltet war. Der Stromfluss wurde unterbrochen, sobald kein Verbraucher die Verbindung kurzschloss.

Ja, es hat funktioniert. Jedoch wurde bei dieser Umsetzung mindestens 4 Fehler begangen. Ein richtiger Elektriker würde da wahrscheinlich noch mehr Fehler finden als ich.

Potenziell tödlich bei der Sache ist, dass eine Spannung an dem blauen Kabel anlag. Dies darf unter keinen Umständen der Fall sein.

Langer Rede kurzer Sinn: Für eine Standardschaltung, für die ich normalerweise 5 bis 10 gebraucht hätte, habe ich mindestens eine Stunde investiert, weil ich immer wieder umdenken musste.

Das gleiche Problem kann auch selbstverständlich auch beim Programmieren auftreten. Man verlässt sich auf Funktionalität, die an der Stelle einfach nicht gegeben ist.

Meine persönliche Top 10 an Missachtungen

10. Falsch gesetzte oder fehlende Klammer

Zugegebenermaßen muss ich gestehen, dass ich bis dato zwei unterschiedliche Stile kannte.

Auf der einen Seite ist es der BSD-Stil bei dem die Klammer immer in einer neuen Zeile steht. Beispiel hierzu wäre:

public string GetNickname(Person person)
{
	if (person.Nickname != "")
	{
		return person.Nickname;
	}
	else
	{
		return person.Firstname;
	}
}

Und den Egyption-Style, welcher auch K&R oder 1TBS genannt wird. Beispiel hierzu:

public string GetNickname(Person person) {
	if (person.Nickname != "") {
		return person.Nickname;
	} else {
		return person.Firstname;
	}
}

Wie man sehen kann, ist der Unterschied, dass bei dem einen die Klammern in eine neue Zeile kommen, bei dem anderen am Ende der Zeile zusammengefasst werden.

Hinzu kommt noch ein Spezialfall, der in beiden Varianten kommen könnte:

public string GetNickname(Person person)
{
	if (person.Nickname != "")
		return person.Nickname;
	else
		return person.Firstname;
}

Das Problem bei der letzteren ist jedoch, dass man nicht wirklich sieht, wozu die Anweisung gehört.

Darüber hinaus gibt es noch weitere Stile. Wikipedia fasst die Klammerstile ein wenig zusammen.

Allein über die Klammerung, gibt es viele Diskussionen, bei denen sich die Entwickler nicht einig sind, z.B. hier und hier.

Jeremy Clark schreibt beispielsweise in seinem Blog dazu, dass man eins auswählen sollte und es konsequent durchziehen sollte.

Dem kann ich nur bedingt zustimmen.

In JavaScript hat sich beispielsweise der 1TBS Style durchgesetzt. In C# der BSD Style. Wobei in PHP unterscheidet sich sogar von Framework zu Framework.

Mein Tipp: Schau dir an, wie es andere Entwickler in Größeren Projekten machen und zieh es genauso durch. Dies spart Zeit, Nerven und riesige sinnlose git commits, bei denen nur ein paar Klammern geändert wurden.

9. Inkonsistente Methoden-Benennung

Dieser Fehler gehört zu meinen Lieblingen.

Als C# Entwickler, habe ich mir angewöhnt Methoden Groß zu schreiben. So heißen beispielsweise in C# meine Methoden so:

class Person
{
	public string GetName()
	{
	}
	
	public int GetAge()
	{
	}
}

In JavaScript, Java und vielen anderen Sprache wäre es falsch. Hier müsste das so heißen:

Java:

class Person
{
	public String getName()	{
	}
	
	public int getAge() {
	}
}

JavaScript:

var Person = (function() {
	return {
		getName: function() {
		},
		getAge: function() {
		}
	}
});

PHP (objektorientiert):

class Person
{
	public function getName()
	{
	}
	
	public function getAge()
	{
	}
}

PHP (prozendural):

public function get_name()
{
}

public function get_age()
{
}

Wie man sieht, gibt es zwar Ähnlichkeiten, aber trotzdem gibt es gravierende Unterschiede.

Das große Problem bei der Sache ist jetzt, dass es teilweise doppelte Methoden geben könnte oder auch ganz einfache inkonsistente Benennung:

Stell dir mal vor, es gibt bereits existenten Code. Der Entwickler hat sich an alle Konventionen gehalten und alles richtig gemacht. Jetzt kommt ein „Kevin“ daher und schreibt eine neue Klasse. Beim Aufruf sieht das dann so aus:

$dataContext = new MySqlConnection();
$dataContext->open();

$repository = new PersonRepository($dataContext);
$people = $repository->getAllPeople();

foreach ($people as $person) {
	echo $person->GetForename() . " " . $person->GetLastname() . "\n";
}

$dataContext->close();

Ganz ehrlich. Das ist doch Mist!

8. Inkonsistente Benennung der Variablen

Bleiben wir doch mal ein wenig beim Thema Benennung. Hier gibt es nämlich teilweise gravierende Unterschiede.

In vielen Sprachen gibt es das Schlüsselwort this.

class Person
{
	public String name;
	public String getName() {
		return this.name;
	}
}

In C# gibt es auch dieses Schlüsselwort. Jedoch ist es ein Relikt aus vergangenen Zeiten und sollte nicht mehr verwendet werden.

Um zu kennzeichnen, ob es sich um eine Instanzvariable (Feld) handelt oder nicht, sollte man ein Unterstrich verwenden. In etwa so:

class Person
{
	public string _name;
	public string GetName()
	{
		return _name;
	}
}

Macht man das nicht, ist die Verwirrung groß, wenn man versucht eine Methode zu analysieren und erst einmal denkt, es handle sich um eine lokale Variable.

Dies hier ist valider Code. Aber wo zur Hölle kommt die Variable current her?

class Counter
{
	public int current;
	public int Increment()
	{
		return current++;
	}
}

Na gut. Steht ja drüber. Was ist jedoch, wenn die Methode aber ca. 50 Zeilen lang ist und die Klasse ca. 500 Zeilen erfasst?

Gut, dann ist beides sowieso zu Groß und muss extrahiert werden. Dennoch sucht man danach zunächst vergeblich.

6. Falsche Benennung von Konstanten und Variablen

Vor ettlichen Jahren, habe ich mal gelernt, man solle bitte Konstanten wie folgt schreiben:

const int EINE_WICHTIGE_ZAHL = 42;

Dies war auch viele Jahre „state-of-the-arts“

Jedoch ist dies nicht für alle Sprachen zutreffend. Natürlich, diese Schreibweise ist immer noch in diversen Sprachen vertreten. Allen vorran viele C-Dialekte.

In C# jedoch ist das nicht mehr der Fall. Hier sollte man stattdessen eine andere Schreibweise verwenden:

const int EineWichtigeZahl = 42;

Und ganz ehrlich. Diese Schreibweise finde ich auch angenehmer zu lesen 🙂

5. Falsche Einrückung

Dies kann höchstens eintreten, wenn man verschieden Entwicklungsumgebungen verwendet und diese auch noch falsch eingestellt hat.

Konkretes Beispiel:

In einer IDE wurde die Einrückung auf 4 Leerzeichen eingestellt. In der zweiten wird mit Tabs eingerückt. Die Tabgröße liegt bei 3.

Herzlichen Glückwunsch, das Chaos ist perfekt. Besonders, wenn in beiden IDEs bereits einiges an Quellcode geschrieben wurde und nun versucht alles vernünftig einzurücken. Schön, bekommt man das auf jeden Fall nicht mehr so wirklich mehr hin.

Tipp: Einrückung mit 3 oder besser, 4 Leerzeichen. Viele Entwicklungsumgebungen wandeln auch ein Tab in 4 Leerzeichen um. Das erspart auf jeden Fall viel Ärger.

4. Keine Einrückung

Bleiben wir noch etwas beim Thema Einrückung und schauen wir uns diesen Quellcode an:

public void Funktion() {
if (bedingung1)
if (bedingung2)
MachMalWas();
MachNochEtwas();
}

Ich hoffe, so etwas schreibt nun nicht wirklich mehr. Aber gerade bei so einem Code-Block sieht man mal wieder, wie wichtig Klammern sind.

In diesem Fall würde nämlich die Funktion „MachNochEtwas“ jedes Mal ausgeführt werden und nicht so wie erwartet nur, wenn beide Bedingungen zutreffend sind.

Die korrekte Einrückung in diesem wäre an der Stelle so:

public double Funktion() {
	if (bedingung1)
		if (bedingung2)
			MachMalWas();
	MalNochWas();
}

Aber auch hier sieht man deutlich, es fehlen die Klammern. Außerdem könnte man auch beide Bedingungen zusammenfassen.

3. Sinnlose Ausdrücke

Der Klassiker schlechthin:

public bool IsStringEmpty(string value) 
{
	if (value == "")
		return true;
	else
		return false;
}

Es wird etwas überprüft und im Erfolgsfall ein true zurückgegeben. Andernfalls ein false.

Warum kürzt man das nicht ab und schreibt das so?

public bool IsStringEmpty(string value)
{
	return value == "";
}

In die gleiche Kategorie gehören übrigens auch sinnlose, runde Klammern in Ausdrücken.

Teilweise können Klammern Sinn ergeben, tun dies jedoch in den seltensten Fällen.

2. Kein Zeilenumbruch

Zum guten Stil ghehört auch so etwas wie: Pro Zeile eine Anweisung. Jedoch lese ich immer noch Quellcode im folgenden Stil:

public bool IsValid(Person person) 
{
	if (person.Forename == "") return false;
	if (person.Surname == "") return false;
	if (!person.Address.IsValid()) return false;
	
	return true;
}

Klar, es sind nur irgendwelche Überprüfungen. Es könnte auch den Eindruck erwecken übersichtlicher zu wirken, tut es aber nicht.

Der Quellcode ist nicht mehr so gut überblickbar. Man muss diesen komplett lesen um nachzuvollziehen was hier genau passiert.

Natürlich ist die saubere Variante länger, das möchte ich auch nicht bestreiten. Jedoch auch deutlich übersichtlicher.

public bool IsValid(Person person) 
{
	if (person.Forename == "")
	{
		return false;
	}
	
	if (person.Surname == "")
	{
		return false;
	}
	
	if (!person.Address.IsValid())
	{
		return false;
	}
	
	return true;
}

Man sieht auf den ersten Blick die komplette Struktur.

1.Die Verwendung von var.

Das ist mein persönlicher Hass-Kandidat überhaupt. Zugegeben, es ist speziell für C#.

Die Rede ist von dem Schlüsselwort var.

In JavaScript gibt es auch das var. Allerdings ist es hier mit einer Variablendeklaration gleichzusetzuen. Man erschafft sich eine neue Variable mit dem Schlüsselwort var und ist anschließend komplett dynamisch.

Ähnliches gilt für PHP. Hier erstellt man sich eine Instanzvariable mit var.

Beide Sprachen sind nicht Typsicher. Richtige Datentypen wie z.B. int oder string werden dynamisch festgelegt und können sogar variieren.

Anders jedoch in C#.

C# ist Typsicher. Aber auch hier verwendet man vermehrt das blöde var. Man hat bis auf die tatsache, dass man sich ein wenig Tipparbeit gespart hat, absolut 0 benefit.

Das folgende Beispiel ist zwar etwas an den haaren herbeigezogen, beschreibt aber ganz gut, warum es sogar Fehleranhällig ist ein var zu verwenden:

var x = 5;
var y = 2;
var z = x / y;

Welchen Wert beinhaltet z?

Wenn du jetzt an 2.5 gedacht hast, muss ich dich sehr stark enttäuschen. Es ist nämlich 2.

Erklärung dazu: 5 ist ein integer. Wenn man in C# eine variable mit var initialisiert, wird der „konkreteste Typ“ verwendet.

Ein int kann man in ein double konvertieren. Andersherum theoretisch auch). Wenn man also die 5 so wie oben abgebildet initialisiert wird, kommt ein int bei rum.

Bei einer Division zweier ints, kommt als Ergebnis ebenfalls ein int heraus. Konvertiert man ein double in ein int, wird der Rest abgeschnitten, da dieser nicht abgebildet werden kann.
Ergo: z wäre ebenfalls ein int und somit eine 2.

Viel Spaß bei der Fehlersuche. Diesen Fehler findet man so gut wie nie.

In Kombination mit einer bescheidenen Benennung wird es noch schlimmer:

var person = dataSource.GetPerson();
var cars = dataSource.GetCars(person);

Welche Datentypen haben jeweils person und cars?

Das geht aus dem Quellcode nicht hervor. Aber genau das ist jedoch manchmal wichtig zu wissen.

Und es ist kein Argument zu sagen: „Dann geh doch mit der Maus drüber und dann siehst du es„.

Fazit

Vor allem, wenn man in größeren Teams arbeitet benötigt man Regeln. Regeln, die jeder befolgt. Ohne solche Regeln würde die Qualität des Quellcodes leiden.

Im ersten Augenblick würde man nicht daran denken, dass allein durch irgendwelche Benennungsregeln die Qualität der Software leidet. Dem ist jedoch so.

Besonders, wenn ein Projekt mittlerweile gewachsen ist, verbringt man mehr Zeit damit Quellcode zu lesen, anstatt neuen Code zu produzieren.

Man liest also den Code einer anderes Kollegen oder auch den eigenen. Das schlimmste ist hierbei jedoch, wenn man sich im Quellcode nicht zurechtfindet und mehr Zeit damit verbringt etwas zu suchen anstelle etwas zu finden.

Mit zunehmender Erfahrung weiß man eigentlich schon ziemlich gut, wo man in einem Projekt das gesuchte findet. Wenn keine Ordnung im Code herrscht, sucht man vergeblich.

Das ist genauso, wie der 10er-Maulschlüssel den man nie findet, wenn man ihn gerade einmal benötigt. Stattdessen findet man immer etwas anderes. Braucht man den jedoch nicht, liegt der immer vor der Nase rum.

Stellt sich dann noch die Frage: Braucht man diese Konventionen in einem kleinen Projekt, an dem man alleine Arbeitet?

Meine klare Meinung: Ja!

Ein kleines Projekt kann auch mal groß werden. Andere Entwickler können mal dazu stoßen. Wenn man den eigenen Quellcode seit geraumer Zeit nicht mehr angepackt hat, kann man auch selbst dieser andere Entwickler sein. Schließlich hat man in der Zwischenzeit etwas dazugelernt und hat eine andere Sichtweise.

Jetzt möchte ich aber deine Meinung dazu hören:

  • Herrschen Konventionen, bzw. Standards in den Projekten an denen du arbeitest?
  • Hältst du dich an allgemeine Konventionen?
  • Was tust du, wenn du mal auf eine andere Sprache umsteigen musst? Behältst du dein Stil bei oder passt du dich an?

Schreib doch in die Kommentare deine Meinung dazu.

Und wie immer nicht vergessen: Teilen 🙂

Kategorien:
Clean Code
Das könnte dir auch gefallen
Sei der erste und teile deine Meinung mit der Welt!
... und was meinst du dazu?
Deine E-Mail-Adresse wird nicht veröffentlicht.