Warum macht ihr das? Wo bleibt der Sinn eures Handelns? Teil 1: Unlesbare Betriebsanleitungen

Es ist eine Erfahrung, die viele von uns nur zu gut kennen: Man kauft ein neues Produkt, öffnet voller Vorfreude die Verpackung und findet eine Betriebsanleitung – die, rein technisch gesehen, vorhanden ist, aber praktisch unbrauchbar bleibt. Warum? Weil die Schrift so winzig ist, dass selbst jemand mit hervorragendem Sehvermögen ohne Lupe oder Mikroskop kaum eine Chance hat, die Inhalte zu entziffern.

Das Beitragsbild zeigt exemplarisch, wovon ich spreche. Doch die entscheidende Frage ist: Warum tun Hersteller so etwas? Warum investiert ein Unternehmen Zeit, Geld, Material und Energie, um etwas zu drucken, das im Endeffekt niemand lesen kann? Welche Logik steckt dahinter?

Eine Betriebsanleitung sollte helfen, Klarheit schaffen und Nutzer unterstützen – und nicht als bloße Pflichtübung beiliegen. Es wird Zeit, dass wir dieses absurde Phänomen hinterfragen und die Hersteller zur Verantwortung ziehen. Auch unseren Umwelt und Klima zu liebe (Ihr wisst schon: CO₂ Global Warmin, Waldbrände, Trinkwasservermangel wegen industrielle Nutzung, Wasser- und Umweltverschmutzung etc. etc.)

Die Sprechblase/Der Tooltip

Neulich müsste ich etwas scannen, und leider müsste ich die Einstellungen des Scanners anpassen. Dabei fiel mir die Schaltfläche „Standard“ auf. Ich positionierte den Mauszeiger darauf, in der Hoffnung der Text in der Sprechblase wurde dessen Funktion etwas genauer erklären …

Was macht diese Schaltfläche? Wo ist die Sprechblase?

Leider wurde keine Sprechblase eingeblendet, und ich zögerte, darauf zu klicken, weil ich befürchtete, alle Einstellungen erneut vornehmen zu müssen.

Die Sprechblase stellt die direkteste und einfachste Verbindung zwischen dem Nutzer und der Dokumentation dar.

Ein informativer Tooltip spart dem Nutzer den Griff zur gedruckten oder digitalen Dokumentation und die anschließende Suche nach einer Erklärung.

Ist die Information über die Funktion einer Benutzeroberfläche (UI) treffend formuliert, erspart sie dem Nutzer:

  • Das Durchsuchen von Benutzerhandbüchern oder PDF-Dateien,
  • Die gezielte Suche nach der Erklärung der betreffenden UI-Funktion (Auf welcher Seite? In welchem Kapitel?),
  • Den Verlust von Konzentration und den Abbruch seines ursprünglichen Vorhabens.

Oft sind sich Nutzer nicht sicher, und eine kurze und klare Tooltip-Information kann dem Nutzer das nötige Vertrauen geben, seine Aktion fortzusetzen, oder ihn davon abhalten, einen möglichen Fehler zu begehen.

Der Tooltip sollte möglichst kurz sein, und nicht versuchen die Dokumentation zu ersetzen.

Modelle

Ein Modell ist eine stark reduzierte, abstrakte Abbildung der Wirklichkeit. Es ist absichtlich unvollständig.

In jenem Reich erlangte die Kunst der Kartografie eine solche Vollkommenheit, dass die Karte einer einzigen Provinz den Raum einer Stadt einnahm und die Karte des Reichs den einer Provinz. Mit der Zeit befriedigten diese maßlosen Karten nicht länger, und die Kollegs der Kartografen erstellten eine Karte des Reiches, die die Größe des Reiches besaß und sich mit ihm in jedem Punkte deckte.
(Jorge Luis Borges, „Von der Strenge der Wissenschaft“ in: Universalgeschichte der Niedertracht und andere Prosastücke, Ffm-Berlin-Wien, ISBN 978-3548029146)

Was ist ein Software-Entwickler oder Techniker der Nichts dokumentiert für eine Firma?

Kurz: Heroin!

Er/Sie macht die Kollegen und die Firma von sich abhängig.

Was passiert, wenn:

  • Dieser Kollege die Firma verlässt?
  • Er längere Zeit krank ist?
  • Er in Pension geht oder stirbt?

Können andere Kollegen die Köpfe zusammenstecken und herausfinden wie seine Komponenten funktionieren? Wie diese sich verhalten oder zu benutzen seien? Oder müssen die Komponenten (die eigenen Produkte der Firma) mithilfe von Reverse-Engineering auf Funktionsweise analysiert werden? Müssen diese Neu/nochmal (von null auf) entwickelt werden?
Muss der gesamte Code gelesen und verstanden werden?
Was kostet die Dokumentation an Zeit und Geld für eine Firma? (A)
Was kostet das Reverse-Engineering des eigenen Produktes + dessen Neu-Entwicklung und/oder lesen des gesamten Codes? (B)
Welche Kosten sind höher: A oder B?
Welche (A oder B) bringt größere, längere und teurere Kaskadeneffekte (Zeitpläne und Ressourcen-Teilung/-Planung, Fertigstellungs-Termine bei parallel laufenden Projekte) mit sich?
Welche (A oder B) bringt die Termine durcheinander, sorgt/stiftet/produziert Chaos, macht Kunden unzufrieden?
Wer zahlt für die entstandene Kosten und Ressourcen-Verbrauch für die Entwicklung eines Produktes das nicht verwendet/eingesetzt werden kann?
Wer zahlt für die entstandene Überstunden bei B?
Wer zahlt für die entstandenen Pönalen/Vertragsstrafen durch B bei N andere Projekte?

Hier eine einfache Milchmädchen-Rechnung (+Diagramm) für besseres Verständnis:


Naive Annahmen:
1. wir leben in einer perfekten Welt (Nichts geht schief, man muss auf Nichts warten, es gibt keine Bugs, niemand wird Krank, keiner nimmt sich Urlaub, … es gibt keine negativen Überraschungen)
2. die Projekte sind voneinander unabhängig und dauern alle gleich (exakt, nur 30 Tage)

Wie man aus dem Diagramm (für eine „perfekte“ Welt) sieht: Die Fertigstellung jedes Projekts verschiebt sich um 15 Tage (Dauer der Neuentwicklung von Komponente/System des Projekts ganz oben) um 15 Tagen nach hinten!
Das bedeutet für alle N Projekte: N × 15 Tage.
In unserem Beispiel, bei 3 Projekten, bedeutet das 45 Tage (eineinhalb Monate) insgesamt.

Wir leben aber in keine perfekte Welt!


1. Manche Projekte sind voneinander abhängig (Projekt A ist von Projekt B abhängig, und Projekt B ist von Projekt C abhängig, usw.): A ⇒ B ⇒ C ⇒ …
2. Krankheit, Urlaub, Todesfall
3. Verzögerung durch Bugs (z. B. Memoryleak)
4. zuständiger Fachexperte für XYZ, der Mitarbeiter X, ist auf einer Baustelle von einem Kunden in Land Y und kommt erst in einer Woche zurück
5. Wegen Covid-19, einem Schiff das in Suezkanal feststeckt, Produktionsverzögerung, Lieferschwierigkeiten für eine Hardware-Komponente, kann man Projekt XY nicht fertigstellen oder testen
6. Die Firma VUDU wird an Firma CONYAK verkauft und ändert die Lizenzierungen für das KI-System von VUDU. Das System muss nun ersetzt werden, oder darauf muss komplett verzichtet werden
7. Es stellt sich in reale Umgebung (Prototyp-System) heraus, dass externes/gekauftes System XYZ für die Aufgabe ABC ungeeignet ist oder dessen Laufzeitkomplexität viel zu hoch als erwartet ist (z. B. Taktzeiten können nicht eingehalten werden, in zeitkritischen Systemen werden harte Zeitschranken durchbrochen)
8. Es wurde aufgrund falscher Annahme(n) viel Code geschrieben, jedoch bei Developer-Tests stellt man am Ende fest: XYZ ist gar nicht imstande ABC zu tun
10. Unterschiedliche Softwareentwickler arbeiten an unterschiedliche Projekte und haben von andere Projekte, dessen Lösungsansätze, Paradigmen und/oder Konzepte keine Ahnung
11. Es gibt Spezialisten für Teilbereiche, nicht jeder kann alles, was der Andere kann. Der Spezialist wird aber für Projekt X benötigt und kann sich nicht auch noch um andere Projekte (Aufgaben) gleichzeitig kümmern
12. Der Tester bzw. die Test-Abteilung muss sich zuerst um Projekt X kümmern. Projekt Y muss warten bis es zum Testen dran ist
13. … und vieles mehr

Wie man in obigem Diagramm sieht:
Die Neuentwicklung des Komponenten/Systems (ganz oben) verursacht enorme Chaos und Verzögerung in Projekt 1, was wiederum enorme Chaos und Verzögerung bei Projekt 2 verursacht.
Da das Projekt 3 von Projekt 2 abhängig ist, braucht man sich nicht wundern, dass die Entwicklung dessen erst nach dessen Liefertermin gestartet werden kann. Obwohl für die Liefertermine für jedes Produkt 10 Tage als Puffer geplant waren (was ich in der Realität leider noch nie erlebt habe!).
Das ist die Folge von: Nichts dokumentieren (weil „die Kunden nicht fürs Dokumentieren Zahlen“).

To comment, or not to comment – that is the question

Eine kurze Geschichte übers Kommentieren und Kommentare

Ich wünsche die Kollegen beim Neuschreiben des Codes in C, C++, C#, Java,… oder WasAuchImmer++ viel Geduld, Kraft und Nervenstärke.
Wenn Kommentare genauso kryptisch sind, wie der Code
Was machen diese 15 Zeilen?
Man kann die Kommentare übersetzen und erahnen was diese Zeilen tun

Back to the Future…
Kommentare sind wichtige Informationen für die Zukunft.
Kommentare sind wichtige Informationen aus der Vergangenheit.
Kommentare sind Notizen/Erklärungs-Ergänzungen für sich selbst, Kolleginnen und die Nachwelt (neue Kolleginnen, wenn man nicht mehr in der Firma (oder am Leben) ist).

Ich lese immer wieder Sätze mit Rufzeichen am Ende, wie „Jede Code-Zeile muss kommentiert werden!“, oder „Pro Methode, mindestens drei Zeilen Kommentare!“ usw.

An der Uni hieß es „Alles muss kommentiert werden!“.

Dann hieß es (eine Show namens „Linux Nerds vs. Geeks“ glaube ich) „Wenn man schönen/guten Code schreibt, braucht man keine Kommentare“ (sagte der Linux Grafik-Programmierer-Guru!).

Irgendwann sagte ein ehemaliger Kollege „Kommentare verwirren nur“ und dass „Nur Amateure und Doofis kommentieren“ …

Mein derzeitiger Standpunkt ist:

  1. Extrem ist und bleibt extrem. Daher entscheide ich mich für die goldene Mitte.
  2. Bevor ich Kommentiere stelle ich mir folgende Fragen:
    1. Muss ich Kommentieren?
    2. Reicht der Name nicht?
    3. Ist der Name gut gewählt?
    4. Sollte ich nicht lieber den Namen ändern?
    5. Wie groß ist der Informationsgehalt des Kommentars?
    6. Bietet der Kommentar eine zusätzliche oder ergänzende Information, die sonst nicht (oder sehr schwer) zu lesen/sehen/wissen (Code) wäre?
    7. Erleichtert/Verkürzt der Kommentar die Suche/Recherche oder das Verständnis des Algorithmus?
    8. Lässt der Kommentar Raum für falsche Interpretationen zu?
    9. Hilft der Kommentar Fehler zu minimieren, oder verursacht es mehr Fehler durch Missverständnis?

Nehmen wir den (C#) Code von Unten als Beispiel und stellen wir uns gemeinsam pro Kommentar die obigen neun Fragen unter Punkt zwei:

public class Person
{
    /// <summary>
    /// Gets/Sets the ID of Person.
    /// </summary>
    public int ID { get; set; }

    /// <summary>
    /// Gets/Sets the first/given name of Person.
    /// </summary>
    public string FirstName { get; set; }

    /// <summary>
    /// Gets/Sets the last/second name of Person.
    /// </summary>
    public string LastName { get; set; }

    /// <summary>
    /// Gets/Sets the day of birth of Person.
    /// </summary>
    public DateTime BirthDay { get; set; }

    /// <summary>
    /// Returns the whole/full name beginning with FirstName then LastName in uppercase.
    /// </summary>
    /// <returns></returns>
    public string GetName()
    {
        // todo: check!
        return $"{FirstName} {LastName.ToUpper()}"; // NG! PGH 2021-07-05 V0.8.15
    }
}

Die Property-Namen sagen eindeutig, unmissverständlich und klar aus, was sie beinhalten, und deren Kommentare haben/bringen keine zusätzliche/ergänzende Informationen… Also ⇒ Weg damit!

Der Kommentar von der Methode „GetName“ möchte, und MUSS, etwas erklären, was der Name leider nicht tut. Zusätzlich verwirrt dieser Kommentar.
Innerhalb der Methode „GetName“ steht ein „todo“ Kommentar, was kein Mensch entschlüsseln kann: „check!“ Check-What? Was soll gecheckt/überprüft werden FirstName, LastName oder Return-Value (string)?
Am Ende der Return-Zeile steht wieder kryptische Buchstaben-Suppe:

  1. NG!“ steht für…??? No Guns? No Game? Next Generation? Not Good? No Grade? Network Grid?
  2. Danach steht „PGH„, meine Initialien plus Datum und anscheinend eine Version:
    1. Gibt es für sowas Versionsverwaltungs-Systemen (CVS, SVN und GIT). Dort kann man all das lesen, von Anbeginn der Zeit (Projekt-Geburt) bis zum letzten Commit: Wer (Name, E-Mail-Adresse) hat, wann (Datum + Uhrzeit mit Millisekunden) was (Verzeichnis, Datei, Zeile) in welche Version geändert (gelöscht, hinzugefügt, umbenannt, ergänzt, entfernt,…) hat.
    2. Was sollen die Kolleginnen damit anfangen? Mehrwert? Informationsgehalt?

Das Ganze könnte man auch so schreiben:

public class Person
{
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDay { get; set; }

    /// <summary>
    /// Returns full name, like: "John DOE", "Alice BOYLE".
    /// </summary>
    /// <returns></returns>
    public string GetFullName()
    {
        return $"{FirstName} {LastName?.ToUpper()}";
    }
}

Ich habe diese Beispiele nicht aus der Luft gegriffen.
Ähnliche, und teilweise noch schlimmere Fälle aus der Praxis (was mir unter die Augen gekommen sind) werde ich noch hinzufügen. Entweder hier oder im neuen Beitrag.

Englisch, Deutsch oder Denglisch?

Der Kunde zahlt fürs Code-Schreiben und nicht fürs Code-Lesen!

In einer Firma, wo alle Software-Entwickler und IT’ler Deutschsprachige waren, hat der Inhaber & CEO uns befohlen alle Kommentare (nur Kommentare) auf Deutsch zu schreiben. Ein Jahr später, nachdem das Projekt im Verzug war und die Entwicklung des Software-Systems nicht schnell genug vorangegangen war, wurden drei neue Software-Entwickler aus Spanien eingestellt. Die neuen Kollegen waren alle sehr gute Software-Entwickler und beherrschten souverän ihr Fach, jedoch verstanden kein Wort Deutsch. Danach wurden noch mindestens fünf weitere Software-Entwickler, ebenfalls aus Spanien, eingestellt…
Nun hatten wir alle Hände voll zu tun. Wir drei Deutschsprachigen müssten alle Kommentare nun auf Englisch übersetzen und ersetzen, anstatt unsere Aufgaben nachzugehen.

In eine andere Firma, hatte ich das „Vergnügen“ Code auf Denglisch zu lesen. Manche Namen waren Deutsch, manche waren Englisch, und der Rest eine beliebige Mischung aus Deutsch und Englisch. Dass alle Programm-Elemente (Interfaces, Klassen, Delegates, Events, Methoden, Properties etc.) in Microsoft .NET Frameworks auf US-Englisch waren, ist natürlich trivial…

Das Lesen der Code war extrem schwierig und eine Herausforderung an/für sich. Beispiel für Variable-Namen:
messValue, measWert, measValue, messWert (diese Namen standen für: measured value, bzw. gemessener Wert).
Auch wenn man alle Namen auf Deutsch schreibt, die Hälfte von Code ist und bleibt auf Englisch, da die Schlüsselwörter und alles Andere in MS .NET Frameworks in US-Englisch ist, wie: string.IsNullOrEmpty(…), PropertyChanged, File.Exist(…), using(var x = new MemoryStream(…)), usw. usf.

Deswegen behaupte ich: Es kann kein Code auf „Deutsch“ geschrieben werden, wenn man das versucht, dann entsteht immer ein Code auf „Denglisch“. Man stelle sich nur vor, jemand würde Denglisch schreiben oder reden:
„I war very froh to sehen you nochmal“.

Ich verwende gerne US englische Namen (Color statt Colour, Synchronize statt Synchronise, usw.). Somit bleibt alles einheitlich, unmissverständlich, eindeutig, klar und der Lese-Fluss bleibt sehr flüssig.

Denglisch kostet mehr Zeit, mehr Zeit zum Lesen und mehr Zeit zum Verstehen.
Je öfter der Code von je mehr Kollegen (wieder)gelesen wird, desto mehr Zeit wird verschwendet!
Zeit ist Geld. Somit verursacht Code auf Denglisch unnötige zusätzliche Kosten.

Der Kunde zahlt fürs Code-Schreiben und nicht fürs Code-Lesen!

Naming-Conventions

Nomen est omen
Namen spielen beim Schreiben von Code eine essenzielle Rolle.
Gut gewählte Namen können viele Grübeleien, Verwirrungen und Missverständnisse sowie Fehler vermeiden, und machen den Code leichter lesbar.
Gute Namen sind:

  • Selbsterklärend
  • Klar
  • Eindeutig
  • Unmissverständlich
  • Einprägsam
  • Sagen genau was das Ding tut oder enthält, nicht mehr und nicht weniger
  • Müssen nicht kommentiert werden

Zum Beispiel hier (C# Code):
Der Klassen-Name sagt aus „Ich enthalte Geometrie-Methoden“, die erste Methode sagt „Ich berechne eine Kreisfläche, wenn du mir die Radius-Länge gibst“, usw.
Man braucht nicht (mit F12 ins Visual Studio) sich den Code innerhalb einer Methode zu lesen, um zu wissen, was es tut.

    public class GeometryCalculator
    {
        public double CalculateCircleSurface(double radiusLength)
        {
            return radiusLength * radiusLength * Math.PI;
        }

        public double CalculateSquareSurface(double sideLength)
        {
            return sideLength * sideLength;
        }
    }

Nomen est omen… eben.

Ugly vs Clean Code (zum Aufwärmen)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ugly.Code
{
    public class GeoCalc
    {
        public double GetCS(double value)
        {

            double val1;
            double calc;


            val1 = value;
            calc = Math.Pow(val1, 2) * Math.PI;


            return calc;


        }

        public double GetSS(double value)
        {

            double val1;
            double calc;


            val1 = value;
            calc = Math.Pow(val1, 2);


            return calc;
        }

        // Some other methods...
    }
}

Warum ist der Code oben „Ugly“?

  1. Ungenutzte „using“ Zeilen
  2. Der Klassen-Name sagt nicht, was die Klasse enthält/anbietet/tut
  3. Die Methoden-Namen sagen nicht, was sie tun oder berechnen/zurückliefern
  4. Die Parameter-Namen sagen nicht, was sie enthalten
  5. Die lokalen Variable-Namen sagen nicht, was sie enthalten
  6. Lokale Variablen kaschieren die Parameter und dessen Werte, machen den Algorithmus schwer verständlich
  7. Unnötige Leerzeilen verlängern unnötig die Methode. Man muss mehr scrollen und mit den Augen rauf & runterschauen.

Die Klasse „GeoCalc“ von Oben, könnte man auch so schreiben:

using System;

namespace Clean.Code
{
    public class GeometryCalculator
    {
        public double CalculateCircleSurface(double radiusLength)
        {
            return radiusLength * radiusLength * Math.PI;
        }


        public double CalculateSquareSurface(double sideLength)
        {
            return sideLength * sideLength;
        }

        // Some other methods...
    }
}