Codedisziplin

Softwareentwicklung » Codedisziplin

Die Probleme großer Softwaresysteme haben ihren Ursprung auf dem aller untersten Level: der Codezeile. Ob eine Codezeile die Software besser oder schlechter im Sinne der Übersichtlichtkeit macht, lässt sich mit folgenden Fragen untersuchen:

 

Gibt es die Zeile schon in ähnlicher Form woanders?

Codeduplizierung ist Verschwendung im softwaretechnischen Sinne. Statt eine Aufgabe an einer Stelle zu erledigen, erledigt man nun die selbe Aufgabe an mehreren Stellen.

Beispiel:

Ein Mikrocontroller hat 4 serielle Schnittstellen. Um sie zu initialisieren muss man in einige Register bestimmte Werte schreiben. Die Prozedur ist bei jeder Schnittstelle die gleiche, einzig die Registeradressen und einzelne Werte, die hereingeschrieben werden, ändern sich.

Lösung durch Codeduplizierung:

Man legt 4 Funktionen an, die sich nur durch die Adressen der Register unterscheiden.

Lösung ohne Codeduplizierung:

Da alle 4 Schnittstellen gleich aufgebaut sind, liegen die Register immer in festem Abstand zu einer gegebenen Basisadresse. Man legt nun eine Funktion an, der man die Basisadresse übergibt. Anhand der bekannten Offsets beschreibt sie die Register.

 

Will man später die Schnittstellen auf andere Art und Weise initialisieren, so muss man die Änderung nur noch an einer Stelle vornehmen.

 

Gehört die Zeile an die Stelle, an der sie gerade eingefügt wird?

Auch wenn die Codezeile zum ersten mal auftaucht, kann sie trotzdem an der falschen Stelle stehen.

Beispiel:

Außer der seriellen Schnittstelle möchte man nun auch den A/D-Wandler des Controllers initialisieren.

Falsche Stelle:

Da man schon eine Funktion zum initialisieren der seriellen Schnittstelle geschrieben hat, kann man sie gleich um die A/D-Wandler-Initialisierung erweitern. Wird später im Projekt die serielle Schnittstelle z.B. durch eine Ethernetschnittstelle ersetzt, wird man nicht schlecht staunen, dass die A/D-Wandlung auf einmal nicht mehr funktioniert.

Richtige Stelle:

Man legt ein neues Modul an, das der Ansteuerung des A/D-Wandlers dient. Dorthinein plaziert man den Code zum initialisieren des A/D-Wandlers

Ebenfalls "beliebt" ist das Überspringen von Abstraktionsschichten bzw. der Verzicht auf deren Erweiterung. Statt beispielsweise das Modul für die serielle Schnittstelle um eine Funktion zu erweitern, die einen String versendet, wird das entsprechende Register gleich auf Applikationsebene angesteuert. Durch dieses Hardwaredetail ist die Applikationssoftware schlecht portierbar und der Applikationsentwickler ist mit unnötigen Details belastet.

 

Ist die Zeile an sich noch durchschaubar?

Viele Programmiersprachen erlauben das endlose kaskadieren von Berechnungen. Dadurch kann schon eine einzige Codezeile undurchschaubar werden. Das ist aber noch harmlos gegenüber Zeilen, die direkt auf Daten in anderen Modulen zugreifen. Dadurch entstehen ungeahnte Abhängigkeiten.

Beschließt der Autor von Modul B intern alle Werte mit 10 zu multiplizieren, der Autor von Modul A (das "heimlich" auf Daten von Modul B zugreift) erwartet aber Rohdaten, so wird Modul A nach der Änderung von Modul B nicht mehr funktionieren. Bestenfalls fällt das in internen Tests auf, schlimmstenfalls beim Kunden.

 

Ebenfalls "beliebt" ist es, an einer Zeile so lange zu "dengeln" bis sie das gewünschte Ergebnis bringt ohne hinterher zu verstehen, warum sie das richtige Ergebnis bringt. Da solches Dengeln meist mit einer Hand voll Werten betrieben wird, ist die Allgemeingültigkeit solcher Zeilen dem Zufall überlassen.

 

Codezeilen können auch dadurch undurchsichtig werden, dass die darin verwendeten Bezeichner nicht gut gewählt sind. Das recherchieren passender Funktions- und Variablennamen fällt oft der Bequemlichkeit zum Opfer.

 

Wird die Zeile irgendwo getestet?

Egal wie lange man schon Software schreibt: man macht Fehler. Und wenn man sie selbst nicht macht, dann eben derjenige, der die Software später weiterentwickelt. Deswegen sollte möglichst jede Codezeile nach jeder Änderung getestet werden. Fügt man eine Codezeile hinzu, so fügt man auch einen entsprechenden Test hinzu. So wachsen die Tests zusammen mit der Software und man kann jederzeit feststellen, ob sowohl die hinzugefügte als auch die bestehende Funktionalität fehlerfrei (geblieben) ist.

Striktere Methoden stellen sogar die Erstellung des Tests vor die Erstellung des Codes, um die Vorprägung durch die bereits erledigte Umsetzung zu vermeiden.