Vorwort
Warum dauert es so lange, bis der Mensch klüger wird?
Spezialprobleme schlechter Programmierer
Die sieben gebräuchlichsten Argumente schlechter Programmierer
Wenige Jahre später
Die nächsten 422 Seiten
I. Hallo Wels Hallo Welt
1. Bin ich hier richtig?
2. Zwischen Hybris und Demut
Schwächen als Stärken
Richtiges muss nicht schwierig sein
II. Programmieren als Verständigung
3. Du bist wie die andern
4. Konventionen
Englisch oder nicht?
Die Steinchen des Anstoßes
Konventionen im Team
5. Namensgebung
Namenskonventionen
Von Byzanz über Konstantinopel nach Istanbul
Was Namen können sollten
Lesbarkeit, Verständlichkeit und Unverwechselbarkeit
Verständlichkeit und Logik
Keine Witze! Keine Coolness!
Der Stoff, aus dem die Namen sind
Vorgänge, Funktionen, Methoden
Suchen und Beschaffen
Anzeigen
Verbinden
Zerlegen
Umwandeln
Anfangen und Aufhören
Auf- und Umräumen
Flüchtiges dauerhaft machen
Nein! Doch nicht!
Vorsicht im Umgang mit
Boolesche Variablen
Objektorientierte Programmierung
Datenbanken
Falsche Freunde
Wie es weitergeht
6. Kommentare
Mehr ist manchmal mehr
Zur äußeren Form von Kommentaren
Dokumentationskommentare
Wann und was soll man kommentieren?
Anzeichen, dass ein Kommentar eine gute Idee wäre
Problematische Kommentare
7. Code lesen
Muss ich wirklich?
Zuerst die Dokumentation lesen
Sourcecode ausdrucken
Zeichnen Sie schematisch auf, was einzelne Programmteile tun
Von oben nach unten, von leicht nach schwer
Lernen Sie Spurenlesen
80/20 ist gut genug (meistens)
Vergessen Sie die Daten nicht
Der Beweis ist das Programm
Gemeinsames Code-Lesen
8. Hilfe suchen
Der richtige Zeitpunkt
An der richtigen Stelle fragen
Die Anfrage richtig strukturieren
An den Leser denken
Nicht zu viel erwarten
Keine unbewussten Fallen stellen
Höflich bleiben – egal, was passiert
9. Lizenz zum Helfen
Der falsche Anlass
Die eigennützige Motivation
Die fehlende Einfühlung
Zu viel auf einmal
Antworten auf konkrete Fragen
Wenn Sie selbst keine Antwort wissen
Wenn Sie mit schlechteren Programmierern zusammenarbeiten
Schlechten Code gefasst ertragen
10. Überleben im Team
Ich war’s nicht!
Der Bus-Faktor
Zusammenarbeit mit Anwendern
Zusammenarbeit mit Freiwilligen
Aussprache von Begriffen
III. Umgang mit Fehlern
11. Unrecht haben für Anfänger
Im Irrtum zu Hause
Fehlerforschung im Alltag
Der Hund hat die Datenbank gefressen!
Der gepolsterte Helm
12. Debugging I: Fehlersuche als Wissenschaft
Systematische Fehlersuche
Beobachtung
Was das Beobachten erschwert
Analyse und Hypothesenbildung
Was das Bilden von Hypothesen erschwert
Test der Hypothesen
Was das Testen von Hypothesen erschwert
13. Debugging II: Finde den Fehler
Fehlermeldungen sind unsere Freunde
Wer will da was von mir?
Diagnosewerkzeuge und -strategien
Die üblichen Verdächtigen
Validatoren, Linting, Code-Analyse
Printline-Debugging
Logging
Debugger
Debuggen in einem IDE-Debugger
Debuggen in einem Kommandozeilen-Debugger
Steppen in einem IDE-Debugger
Steppen in einem Kommandozeilen-Debugger
Debugging in deklarativen Sprachen
SQL
Regular Expressions
CSS
Wenn sonst nichts hilft
Wenn auch das nicht hilft
Nach der Fehlersuche ist vor der Fehlersuche
Die häufigsten Fehlerursachen schlechter Programmierer
14. Schlechte Zeichen oder Braune M&Ms
Zu große Dateien
Sehr lange Funktionen
Zu breite Funktionen
Tief verschachtelte if/then-Bedingungen
Mitten im Code auftauchende Zahlen
Komplexe arithmetische Ausdrücke im Code
Globale Variablen
Reparaturcode
Eigene Implementierung vorhandener Funktionen
Sonderfälle
Inkonsistente Schreibweisen
Funktionen mit mehr als fünf Parametern
Code-Duplikation
Zweifelhafte Dateinamen
Leselabyrinth
Ratlose Kommentare
Sehr viele Basisklassen oder Interfaces
Sehr viele Methoden oder Member-Variablen
Auskommentierte Codeblöcke und Funktionen
Browservorschriften
Verdächtige Tastaturgeräusche
15. Refactoring
Neu schreiben oder nicht?
Wann sollte man refakturieren?
Anzeichen dafür, dass Überarbeitungen jetzt kein Fehler wären
Eins nach dem anderen
Code auf mehrere Dateien verteilen
Ein Codemodul in kleinere aufspalten
Nebenwirkungen entfernen
Code zusammenfassen
Bedingungen verständlicher gestalten
Die richtige Schleife für den richtigen Zweck
Schleifen verständlicher gestalten
Variablen kritisch betrachten
Refactoring von Datenbanken
Was man nebenbei erledigen kann
Ist das jetzt wirklich besser?
Wann man auf Refactoring besser verzichtet
Ein Problem und seine Lösung
16. Testing
Warum testen?
Testverfahren
Systemtests (Klicktests)
Unit-Tests
Assertions
Test-Suites
Fixtures
Datenvalidierungen
Performancetests
Richtig testen
17. Warnhinweise
GET und POST
Zeichenkodierung
Zeitangaben
Kommazahlen als String, Integer oder Decimal speichern
Variablen als Werte oder Referenzen übergeben
Der schwierige Umgang mit dem Nichts
Rekursion
Usability
18. Kompromisse
Trügerische Tugenden
Zukunftssicherheit
Geschwindigkeit
Perfektion, Schönheit, Eleganz
Absolution: Wann Bad Practice okay ist
IV. Wahl der Mittel
19. Mach es nicht selbst
Der Weg zur Lösung
Bibliotheken
Umgang mit Fremdcode
Beliebte Fehler im Umgang mit Fremdcode
Was man nicht selbst zu machen braucht
Was man auf keinen Fall selbst machen sollte
Drei Lösungen für ein Problem
20. Werkzeugkasten
Editoren
Welche Programmiersprache ist die richtige?
REPL
Diff und Patch
Paketmanager
Frameworks
Wahl des Frameworks
Warnzeichen beim Umgang mit Frameworks
Entwicklungsumgebungen
Projektverwaltung
Codechecker
Codevervollständigung
Unterstützung der Arbeitsorganisation
Suchen und Refactoring
Nachteile
21. Versionskontrolle
Alternativen
Arbeiten mit einem VCS
Konflikte auflösen
Welches Versionskontrollsystem?
Subversion
git
Gute Ideen beim Arbeiten mit Versionskontrolle
Schlechte Ideen beim Arbeiten mit Versionskontrolle
Versionskontrollsysteme als Softwarebausteine
22. Command and Conquer – vom Überleben auf der Kommandozeile
Mehr Effizienz durch Automatisierung
Unsere langbärtigen Vorfahren
Windows
Was jeder Programmierer wissen sollte
Optionen
Argumente
Wohin mit dem Ergebnis?
Ergebnisse verketten
Wildcards
Navigation
Dateien
Betrachten
Suchen und Finden
Ressourcen schonen
Zusammenarbeit
Zeitsteuerung
Editieren auf dem Server
Internet
Muss ich mir das alles merken?
Not the whole Shebang!
23. Objektorientierte Programmierung
Vorteile der objektorientierten Programmierung
Die Prinzipien objektorientierter Programmierung
Modularität und Abschottung
Abstraktion
Polymorphismus
Vererbung
Sinnvoller Einsatz von OOP
Nachteile und Probleme
Unterschiedliche Objektmodelle, je nach Sprache
Objektorientierte Programmierung und Weltherrschaftspläne
24. Aufbewahrung von Daten
Dateien
CSV/TSV
XML
JSON
YAML
Versionskontrollsysteme
Datenbanken
Suchen und Finden
Relationale Datenbanken
NoSQL-Datenbanken
Document Store-Datenbanken wie CouchDB oder MongoDB
Graphdatenbanken wie neo4j
25. Sicherheit
Wichtige Konzepte
Vor- und Nachteile der Offenheit
Vom Umgang mit Passwörtern
Authentifizierungsverfahren
SQL Injection und XSS – die Gefahren in User-Content
Weiße Listen sind besser als schwarze
Alle Regler nach links
Auch die Hintertür abschließen
Penetration Testing
Die Fehler der anderen
Sicherheit ist ein Prozess
26. Nützliche Konzepte
Exceptions
Error Handling
State und Statelessness
IDs, GUIDs, UUIDs
Sprachfamilien
Variablentypen
Trennung von Inhalt und Präsentation
Trennung von Entwicklungs- und Produktivserver
Selektoren
Namespaces
Scope von Variablen
Assertions
Transaktionen und Rollbacks
Hashes, Digests, Fingerprints
CRUD und REST
27. Wie geht es weiter?
Was ist ein guter Programmierer?
Zum Weiterlesen
Danksagungen
Stichwortverzeichnis
»Von ungezählten Dingen weiß man, dass man sie nicht weiß. Die Anzahl der Dinge, von denen man weiß, dass man sie nicht weiß, soll mal als verwickeltes Beispiel dienen. Das ist nicht weiter schlimm, denn wenn man weiß, dass man etwas nicht weiß, fragt man einfach Google, fertig. Schwieriger wird’s, wenn man nicht weiß, was man nicht weiß. Diese Sorte Nichtwissen ist leider eine offene Tür für heftige Überraschungen.«
—Kai Schreiber, »Riesenmaschine – Das brandneue Universum«
»Wir sollten alle danach streben, bessere Programmierer zu werden; wenn Ihnen dieser Ehrgeiz fehlt, ist dieses Buch nichts für Sie«, heißt es in der Einleitung zu Pete Goodliffes »Code Craft«. Unser Buch hingegen gibt es, weil es vielleicht genau dieser Ehrgeiz ist, der Ihnen fehlt. Beziehungsweise fehlt er Ihnen vermutlich nicht einmal. Sie haben andere Prioritäten, und ein besserer Programmierer zu werden, kommt auf der Liste Ihrer Ziele im Leben frühestens auf Platz 8. Wenn Sie sich trotzdem gern etwas weniger häufig ins Knie schießen würden als bisher, dann sind Sie hier richtig.
Sie möchten Ihre Programmierkenntnisse pragmatisch ausbauen, haben aber nicht das Bedürfnis, gleich als Referenz für guten Programmierstil zu gelten. Sie haben nicht vor, Softwarearchitekt oder Gruppenleiter für Software in einer Firma zu werden, sondern wollen ein paar alltägliche Probleme lösen, ohne jemanden dafür bezahlen zu müssen.
Eventuell sind Sie weit davon entfernt, sich »Programmierer« zu nennen. Weil Programmierung keine Geheimwissenschaft für Spezialisten mehr ist, haben Sie ein bisschen damit herumgespielt, ob nun zu Ihrem Privatvergnügen oder um sich eine ganz andere Arbeit zu erleichtern. Sie haben das eine oder andere Programm geschrieben und beherrschen mindestens eine Programmiersprache so lala. Für Probleme finden Sie Lösungen, haben aber das Gefühl, dass das bestimmt alles irgendwie besser ginge. Nachträglichen Anpassungen gehen Sie so lange wie möglich aus dem Weg, weil es Ihnen schwer fällt, Ihren eigenen Code aus dem Vorjahr zu verstehen. Sie fragen sich, ob das wohl allen so geht.
Oder aber Sie halten sich trotz geringer Erfahrung für einen ziemlich begabten Programmierer, der nur gelegentlich auf kleine Schwierigkeiten stößt. Das ist das Stadium der »unbewussten Inkompetenz«, und laut den Interviews, die wir für dieses Buch geführt haben, kann dieser Zustand zehn bis fünfzehn Jahre lang anhalten:
»Ich habe von den 19 Jahren, die ich programmiere, sicher 13 Jahre sehr schlecht programmiert. Es mussten erst mal Probleme einer bestimmten Größe entstehen, die mich dann zum Umdenken gezwungen haben. Wenn man anfängt, Sachen für andere zu machen, und dann immer noch schlecht ist oder die Abkürzungen nimmt, die man sich halt so angewöhnt hat, dann kann es sein, dass die Sachen sehr schnell zusammenbrechen. Weil die Leute die Software ganz anders benutzen, weil sie die ganzen Fehler nicht kennen und sie auch nicht automatisch umgehen. Da bin ich durch sehr sauren Regen gegangen und hatte viele schreiende Kunden am Telefon. Ich wusste nicht, dass ich ein schlechter Programmierer bin. Ich dachte, was ich kann, reicht völlig aus. Aber der persönliche Stress mit den Leuten ist mir auf die Nerven gegangen. Ein Projekt ist krass gescheitert, das war für mich eine persönliche Niederlage, da dachte ich: So geht’s nicht weiter, wie kann man das besser machen? Danach ging’s dann schnell bergauf.«
—Lukas Hartmann, Softwareentwickler
In der Entwicklungspsychologie gibt es seit den 1970ern ein Modell für die Entwicklung von Verständnis und Fähigkeiten in komplexen Wissensgebieten, die »Vier Stufen der Kompetenzentwicklung«[1]. Auch wenn diese Abstufung wissenschaftlich nur mäßig fundiert ist, illustriert sie ganz gut die Entwicklung eines Programmierers vom Anfänger zum Spezialisten.
Die erste Stufe ist die unbewusste Inkompetenz, bei der man weder die Konzepte des Wissensgebietes kennt noch weiß, dass man Defizite hat. Auf die unbewusste Inkompetenz folgt die bewusste Inkompetenz: Man hat zwar immer noch große Schwierigkeiten, die anfallenden Probleme zu lösen, ist sich aber dessen bewusst. Möglicherweise haben Sie diesen Schritt schon hinter sich; schließlich hätten Sie sonst keinen Grund, dieses Buch zu lesen. Vielleicht haben Sie Ihren Code anderen Menschen gezeigt und wurden ausgelacht, vielleicht haben Sie einmal zu oft versehentlich die projektentscheidende Datenbank gelöscht, oder vielleicht sind Sie einfach von Natur aus ein bescheidener Mensch. Auf die beiden Inkompetenzstufen wiederum folgt die »bewusste Kompetenz«: Man kann alles Nötige, muss sich aber noch stark auf die richtige Ausführung konzentrieren. Ganz zum Schluss erreicht man die Stufe der »unbewussten Kompetenz«. Jetzt läuft alles wie von allein. Nach der Lektüre dieses Buches sollten Sie sich in der bewussten Inkompetenz ganz zu Hause fühlen und hin und wieder einen Anflug bewusster Kompetenz verspüren.
Insgeheim halten Sie sich womöglich für ein bisschen langsamer, dümmer oder technisch untalentierter als andere Menschen. In Wirklichkeit aber ist die Welt voll mit hauptberuflichen Programmierern, die Schwierigkeiten haben, eine einfache Bierdeckelrechnung im Kopf durchzuführen. Ein schlechter Programmierer ist nicht schlecht, weil er noch nicht lange programmiert, weil sein IQ nicht hoch genug ist, weil er ein schlechtes Gedächtnis hat, weil er Autodidakt ist oder weil er erst spät im Leben mit dem Programmieren angefangen hat. All diese Faktoren spielen entweder keine große Rolle oder können einem, richtig eingesetzt, sogar zum Vorteil gereichen (dazu später mehr). Ein schlechter Programmierer ist man vor allem, weil man schlecht programmiert.
Wahrscheinlich wissen Sie über viele Probleme Ihres Codes ganz gut Bescheid. Vielleicht haben Sie sogar eine Vorstellung davon, was Sie in Zukunft tun oder unterlassen müssten, um ein besserer Programmierer zu werden. »Es ist keine Schande, ein schlechter oder mittelmäßiger Programmierer zu sein«, schreibt Steve McConnell in »Code Complete«, »die Frage ist nur, wie lange man schlecht oder mittelmäßig bleibt, nachdem man erkannt hat, wie es besser ginge«[2]. Aber warum ist es oft so schwer, den Schritt von der Einsicht zur Problembehebung zu tun?
Die meisten Ursachen für die Beharrlichkeit, mit der wir auf falsche Lösungswege setzen, liegen nicht in der Natur des schlechten Programmierers, sondern in der des Menschen. An erster Stelle steht dabei der Konservatismus. Gegen den Wunsch, einfach immer so weiterzumachen wie bisher, ist erst einmal nichts einzuwenden. Das Gehirn muss mit seinen Kräften haushalten und tut deshalb gut daran, eine akzeptable Lösung nicht gleich wieder über Bord zu werfen, nur weil am Horizont irgendetwas anderes auftaucht. Und allen relevanten Entwicklungen neuer Technologien, Sprachen, Methoden und Frameworks zu folgen, ist eine so aufwendige Beschäftigung, dass kaum Zeit für vielleicht noch unterhaltsamere Aspekte des Lebens bleibt.
Während Kinder und Jugendliche große Teile des Tages damit verbringen, Neues herauszufinden, kann es vorkommen, dass man als erwachsener Mensch über lange Zeiträume fast gar nichts dazulernt. »Ach, das ging doch bisher auch so«, sagt sich der schlechte Programmierer, weil er keine Lust hat, sich eine bessere Welt vorzustellen, in der es weniger als einen Tag dauert, alle Kleinbuchstaben eines Textes in Großbuchstaben zu verwandeln – inklusive der Umlaute. Denn wir haben es nicht nur mit dem Hang zu tun, bei einer bewährten Lösung zu bleiben, sondern auch mit dem nachvollziehbaren Wunsch, möglichst wenig nachzudenken. Wer ohne großes Nachdenken vor sich hinbastelt, kommt zwar nur langsam ans Ziel, erzeugt aber mit jedem Schritt sichtbare Ergebnisse. Denkt man über ein Problem erst einmal nach, wird man es zwar am Ende in einem Bruchteil der Zeit lösen, muss aber damit leben, in den ersten Stunden, Tagen oder Wochen überhaupt nichts Vorzeigbares zu produzieren. Diese Unlust, ins Dazulernen zu investieren, fällt unter Trägheit – obwohl das resultierende Verhalten paradoxerweise nach Fleiß und Arbeit aussieht. Der nachdenkliche Programmierer ähnelt währenddessen über lange Zeiträume verdächtig einem Menschen, der auf dem Balkon sitzt und mit glasigem Blick in die Wolken starrt oder tagelang das Internet durchliest.
Ein Teil der Unwilligkeit, dazuzulernen, entspringt auch aus Angst: Angst vor dem Neuen, Angst vor dem Unbekannten, Angst vor dem Komplizierteren, Angst vor der Dequalifizierung. Wer das bisherige Framework, die bisherige Programmiersprache weiterverwendet, sieht vor sich selbst und anderen wenigstens halbwegs kompetent aus. Auf einem neuen Gebiet wäre man plötzlich wieder Anfänger. Im Vergleich zur Angst, in einer unbeleuchteten Höhle von Zombies aufgefressen zu werden, handelt es sich dabei zwar um eine sehr überschaubare Besorgnis, aber oft reicht auch sie schon aus, um uns von der Beschäftigung mit dem Unbekannten abzuhalten.
Schlechte Programmierer haben wie alle Menschen mit diesen Hindernissen beim Klügerwerden zu kämpfen. Aber für sie kommen noch ein paar eigene Probleme hinzu. Zunächst einmal überfordern sie sich häufig. Wenn man erst als Erwachsener mit dem Programmieren anfängt – und nicht wie viele hauptberufliche Programmierer im Alter von sieben Jahren –, wird man sich nicht damit zufriedengeben, ein Klötzchen auf dem Bildschirm hin- und herspringen zu lassen. Man hat wahrscheinlich ein konkretes Erwachsenenproblem vor Augen, das man lösen will, zum Beispiel Börsenkurse nach Auffälligkeiten zu durchforsten. Und man wird mit seinen beschränkten Fähigkeiten dabei das interessanteste Unheil anrichten.
Nebenbei-Programmierer neigen außerdem dazu, ihren Code vorsichtshalber niemandem zu zeigen. Dadurch entfällt nicht nur das motivierende Element Scham bzw. Angeberei, sondern auch eine der einfachsten Möglichkeiten, dazuzulernen, nämlich das Lernen von besseren Programmierern. Häufig ist eine kurze Erklärung eines erfahrenen Programmierers mehr wert als wochenlanges Nachlesen – nach Konzepten, die man nicht kennt, kann man nicht suchen. Aber jemand, der sie schon kennt, weiß möglicherweise, an welchen Stellen sie dem Anfänger das Leben erleichtern könnten, und kann sie ihm dann mitsamt ihren Vorteilen für die konkrete Fragestellung erklären.
Ein weiterer Punkt ist die Furcht vor dem eigenen Code: Einerseits erkennt man die Notwendigkeit, den Code neu zu strukturieren, um ihn verständlicher zu machen. Aber es dominiert die Angst, aus undurchschaubarem Code, der die richtige Lösung liefert, durchschaubaren Code zu machen, der aber womöglich ein falsches Ergebnis produziert. Dass diese Angst durchaus berechtigt sein kann, spiegelt sich in der Maxime »Never change a running system« wider. Wenn das System aber gar nicht so funktioniert, wie man es gerne hätte, wird aus der pragmatischen Ruhe eine problematische Scheu vor dem Code.
Schließlich ist auch die Vorstellung »Ach, das geht mich alles nichts an, ich programmiere ja nur so zum Spaß« der Weiterentwicklung nicht dienlich. Dahinter steckt die Vorstellung, das Dazulernen oder das bessere Programmieren mache weniger Spaß als das von Wissen unbelastete Herumbasteln. Dabei stimmt das gar nicht. Unerfreulich ist lediglich der Moment der Einsicht, dass man etwas falsch macht. Im schlimmsten Fall folgt darauf noch etwas geistige Gymnastik bei der Einarbeitung in eine neue Technik. Die dabei investierte Zeit spart man an anderer Stelle mehrfach wieder ein – und zwar dann, wenn man nicht mehr ganze Nächte damit zubringt, den unverständlich gewordenen eigenen Code zu entwirren. Was nämlich, wenn man ehrlich ist, so viel Spaß auch wieder nicht macht.
Den Code sieht ja eh niemand außer mir
Schon morgen kann man jemandem begegnen, der sich nichts dringender wünscht, als an diesem herrlichen Projekt mitzuarbeiten. Bonuspunkte, wenn es sich dabei um jemanden handelt, der kein Deutsch kann, der Code aber voller deutscher Variablennamen und Kommentare ist.
Aus »Den Code sieht niemand außer mir« wird schnell »Den Code darf niemand außer mir sehen«. Das führt dazu, dass man sich unnötig an Projekte klammert, mit denen man eigentlich überfordert ist oder die einen längst langweilen. Nach Jahren der guten Codeüberarbeitungsvorsätze verlässt man dann den Arbeitsplatz oder das Projekt schließlich doch einfach so. Die unbetreute und unbetreubare Software stirbt einen sinnlosen Tod.
Dass man selbst den eigenen Code sehen muss – und zwar Jahre später, als klüger gewordener Mensch –, ist schlimm genug.
Die Software benutzt ja eh niemand außer mir
Schon kurze Zeit später wird man diesen Gedanken vergessen haben; man wird aber auch vergessen, die nötigen Sicherheitsfunktionen nachzurüsten.
Auch Sie selbst werden demnächst ein anderer Mensch sein, der sich gar nicht mehr daran erinnert, was bei der Nutzung dieser Software alles zu beachten war.
Später mach ich das alles noch mal ordentlich
Eine Grundregel des Universums: Provisorien halten am längsten. So ist praktisch garantiert, dass man ausgerechnet den Code, den man am gedankenlosesten hingeschludert hat, bis ins hohe Alter wiederverwenden wird.
In 90 Prozent aller Fälle kommt dieses »Später« nie, weil erstens neue Projekte auftauchen, die die ganze Zeit und Aufmerksamkeit in Anspruch nehmen, zweitens niemand Lust hat, gammeligen Code anzufassen, und man drittens gerne verdrängt, wie schlecht der Code ist. Manchmal fängt bereits vor diesem »Später« total überraschend ein neues Jahrtausend an und stellt unerwartet hohe Speicherplatzforderungen für Jahreszahlen, die sich auf die Schnelle nur schwer erfüllen lassen.
Das ist halt ein ganz kompliziertes Problem, da geht es nicht anders, ich muss acht ineinandergeschachtelte Schleifen verwenden
Auch bei einem komplizierten Problem sollte niemand acht ineinandergeschachtelte Schleifen verwenden.
Gerade bei einem komplizierten Problem sollte niemand acht ineinandergeschachtelte Schleifen verwenden.
Bei genauerem Hinsehen ist ein komplexes Problem lediglich ein Bündel mehrerer mittelkomplexer Probleme, und die wiederum bestehen aus wenig komplexen Problemen, die sich aus trivialen Problemen zusammensetzen. Man braucht also nur eine große Anzahl simpler Funktionen zu schreiben (noch besser: bereits von anderen Menschen geschriebene zu benutzen), und schon ist das komplexe Problem gelöst.
Ich merke mir einfach, dass ich bestimmte Eingaben nicht machen darf
Nein, tun Sie nicht. Gerade wenn es hektisch wird, Sie überraschend gebeten werden, der Weltpresse Ihre Erfindung zu präsentieren, oder Sie ein anderes, kompliziertes Problem debuggen, werden Sie genau die Eingaben machen, die Ihre Datenbank in Stücke fallen lassen.
Andere Programmierer, die neuerdings an Ihrem Projekt mitarbeiten (s.o.), können nicht erahnen, dass bestimmte Eingaben tabu sind.
Ich denke schon dran, das rechtzeitig wieder auszukommentieren
Dieser feste Vorsatz hat schon zu romantischen Debug-Nächten im Scheine des Monitors geführt, als Sie noch gar nicht geboren waren. Warum sollte es Ihnen anders gehen? Ein Programmierprojekt im Kopf zu halten, ist schon schwer genug, wenn man sich nicht merken muss, dass irgendwo noch ein paar entsicherte Handgranaten rumliegen.
Es ist ja nur ein ganz kleines Projekt
Projekte haben mehrere Dimensionen. Code, der nur ein eng umrissenes Problem lösen soll, bleibt oft über viele Jahre hinweg im Einsatz. Das Projekt ist dann zwar nicht groß, aber lang.
Am Anfang ist jedes Projekt klein. Bei schlechten Programmierern sorgt die Einstellung »Es ist ja nur ein ganz kleines Projekt« ganz von allein dafür, dass das Projekt niemals groß werden kann. Es erstickt lange vorher an seiner eigenen Unübersichtlichkeit.
Was braucht man also, um ein weniger schlechter Programmierer zu werden? Nicht viel. Neugier ist hilfreich, ebenso wie ein entspannter Umgang mit der eigenen Ahnungslosigkeit – zum Beispiel dann, wenn man sich entschließen muss, andere um Rat zu bitten. Man braucht die Bereitschaft, geduldig Dinge nicht zu verstehen. Man muss Texte lesen, die man nicht durchschaut, und man muss hinnehmen, dass man sich noch kein funktionierendes Modell der Realität bilden kann. Man darf sich nicht darüber ärgern, dass man nach zwei Stunden Beschäftigung mit einem neuen Konzept immer noch nicht begreift, wovon der Autor von »C++ über Nacht« eigentlich schreibt.
Lernen ist ein langwieriger Prozess. Es dauert viele Jahre – manche sagen, ein Leben lang. Wesentliche Dazulernvorgänge lassen sich zwar etwas beschleunigen, aber sie brauchen trotzdem ihre Zeit. Joe Armstrong, der Erfinder der Programmiersprache Erlang, erklärt in »Coders at Work«, wie er im Laufe seines Lebens klüger wurde: Am Anfang seiner Laufbahn musste er ein Programm erst schreiben, um herauszufinden, ob es funktioniert. 20 Jahre später kann er sich dasselbe einfach denken. Zeit spart er dadurch allerdings nicht – die Ausprobiermethode dauert ein Jahr, die Nachdenkmethode auch –, er muss nur weniger tippen.[3]
Die Lektüre dieses Buchs wird Sie also keineswegs gleich klüger machen. Auch nicht zu einem guten Programmierer. Am Ende des Buchs werden Sie im günstigsten Fall ein weniger schlechter Programmierer geworden sein. Ein weniger schlechter Programmierer weiß, dass er das, was er heute anrichtet, morgen selbst ausbaden wird. Er erkennt, an welchen Stellen er sich das Leben kurzfristig leichter und langfristig dafür sehr viel schwerer macht. Er nimmt Rücksicht auf seine eigene Fehlbarkeit. Ein weniger schlechter Programmierer ist dazu bereit, seinen Code anderen zu zeigen und sich Kritik anzuhören. Er beginnt, Verantwortung für seine Taten zu übernehmen. Er sagt nicht »Die API ist unausgereift«, »In PHP geht es nicht besser«, »Das liegt an Fehlern in der Library, für die ich nichts kann« oder »Es musste halt schnell gehen«. Sogar bei wirklich unverschuldeten Problemen fühlt sich der weniger schlechte Programmierer selbst zuständig und bemüht sich um Verbesserungen. Er tut einfach nicht wider besseres Wissen das Falsche.
Oder wenigstens nicht mehr ganz so oft.
Dieses Buch enthält relativ viel Text und nur wenige Codebeispiele. Dass es konkrete Anleitungen für das Schreiben besseren Codes da draußen gibt, wissen Sie ja wahrscheinlich. Aber irgendetwas hat Sie bisher daran gehindert, eine solche Anleitung ausfindig zu machen und zu beherzigen. Unser Buch befasst sich mit den Gründen für diese Scheu vor dem Dazulernen und soll die schlimmsten Probleme auf eine Art lindern, die möglichst wenig Arbeit verursacht.
Der erste Teil, Teil I, beschäftigt sich mit der Gratwanderung zwischen Selbstzweifeln und Selbstüberschätzung und dem Weg von der unbewussten zur bewussten Inkompetenz. Im zweiten Teil, Teil II, geht es darum, wie man sich selbst und anderen Menschen klarmacht, was man mit dem Code eigentlich bezweckt – oder in einer fernen Vergangenheit, also letzte Woche, einmal bezweckt haben könnte. Der dritte Teil, Teil III, handelt vom Unrechthaben und seinen Problemen. Wie kann man mit demselben Kopf, der einen Fehler verursacht hat, diesen Fehler erkennen, beheben und vielleicht sogar in Zukunft vermeiden? Im vierten Teil, Teil IV, geht es um den Werkzeugkasten des Programmierers. Was braucht man nicht selbst zu machen, was sollte man auf keinen Fall selbst machen? Nach der Lektüre werden Sie vielleicht immer noch nicht objektorientiert programmieren oder eine Entwicklungsumgebung einsetzen wollen, aber zumindest wissen Sie dann, wozu diese Werkzeuge erfunden wurden und bei welchen Aufgaben Sie sich Arbeit sparen könnten, wenn Sie eines Tages Ihre Meinung ändern.
Am Ende einiger Kapitel und am Ende des Buchs geben wir Tipps zum Weiterlesen. Wenn es einen deutschen Wikipedia-Eintrag zu einem Thema gibt und er gut ist, verweisen wir darauf; wenn nicht, auf den englischen. Falls die Welt so viele schlechte Programmierer beherbergt, wie die inoffizielle Marktforschung der Autoren nahelegt, könnte sich das Buch gut genug für eine zweite Auflage verkaufen. Sie helfen uns und den zukünftigen Lesern, wenn Sie gefundene Fehler, Kritik und Verbesserungsvorschläge an wenigerschlechtprogrammieren@kulturindustrie.com schicken.
[1] Siehe en.wikipedia.org/wiki/Four_stages_of_competence.
[2] »Code Complete«, S. 825.
[3] »Coders at Work« von Peter Seibel (Apress 2009), S. 215.
Kapitel 1
Kapitel 2
Um herauszufinden, ob dieses Buch für Sie geschrieben ist, nehmen Sie sich ein paar Augenblicke Zeit und lesen Sie sich die unten stehenden Fragen durch. Antworten Sie ehrlich und ohne lange zu überlegen. Wenn Sie eine Antwortmöglichkeit gar nicht verstehen, machen Sie sich keine Gedanken, sondern wählen eine andere.
Ich schreibe meine Programme ...
in Notepad.
im Browser.
in irgendwas anderem.
Wenn etwas nicht funktioniert ...
poste ich eine Fehlerbeschreibung mit dem Titel »Hilfe!!!« unter exakter Nennung aller verwendeten Hardwarekomponenten in einem passenden Forum.
baue ich viele »print«-Zeilen ein, die mir den Inhalt von Variablen ausgeben.
debugge ich mit GDB
Zur Versionskontrolle benutze ich ...
gar nichts. Wenn ich versehentlich was lösche, muss ich es neu schreiben. Deshalb passe ich immer sehr gut auf.
SVN.
Git oder mercurial.
Ich kommentiere meinen Code ...
nie, weil ich nicht so viel tippen will.
nie, weil ich meinen Code für selbsterklärend halte.
nie, weil mein Code selbsterklärend ist.
Wenn ich einen XML-Parser brauche ...
nehme ich mir ein Wochenende Zeit und schreibe einen, wie schwer kann das schon sein.
Ich brauche keinen XML-Parser.
Ich lese die Wikipedia-Einträge zu SAX- und DOM-Parsern durch, sehe mir verschiedene Bibliotheken und deren Bindings an meine verwendete Programmiersprache an, wäge ihre Vor- und Nachteile ab und finde heraus, ob es eine lebendige Community dazu gibt.
Um E-Mail-Adressen zu validieren ...
schreibe ich schnell zwei Zeilen hin, die ich an meiner eigenen Mailadresse überprüfe.
teste ich, ob ein @-Zeichen enthalten ist.
google ich nach einer Regular Expression, auf deren Korrektheit sich namhafte Projekte verlassen.
Mein Code und das Licht der Öffentlichkeit
Ich halte meinen Code geheimer als ein Messie seine Wohnung.
Wenn jemand Code von mir sieht, der schon ein halbes Jahr alt ist, dann ist mir das ein bisschen peinlich.
Mein Code ist Teil des Linux-Kernels.
Ich teste meinen Code ...
gar nicht. Wenn etwas nicht mehr funktioniert, merke ich das schon früher oder später.
nach jeder Änderung an meinem Code.
gar nicht. Nach jeder Änderung an meinem Code prüfen automatisierte Unit-Tests, ob noch alles funktioniert.
Wie sieht ein geeignetes Datumsspeicherformat aus?
Wie schon, »T.M.JJ« natürlich!
Die vergangenen Sekunden seit 00:00 Uhr Koordinierter Weltzeit am 1. Januar 1970, wobei Schaltsekunden nicht mitgezählt werden, gespeichert in einem 64-Bit-Integer.
ISO 8601.
Optimierung ...
ist mir egal.
betreibe ich so lange, bis das Programm auf meinem 2,4 GHz Core 2 Duo mit 256MB 2nd Level Cache in 43.3485 Taktzyklen durch ist.
ist mir so lange egal, wie die User Experience nicht durch Wartezeit beeinträchtigt wird.
Alle anderen Programmierer ...
sind besser als ich.
sind schlechter als ich.
Mal so, mal so.
Ich überarbeite meinen Code ...
nie, ich nehme mir aber hin und wieder vor, alles noch mal neu und besser zu schreiben.
in einem winzigen Schritt nach dem anderen, wenn ich gerade viel Zeit habe.
in einem winzigen Schritt nach dem anderen, auch wenn ich gerade wenig Zeit habe.
Überschlagen Sie jetzt grob, ob Sie mehr als die Hälfte der Fragen mit a) oder b) beantwortet haben. Wenn ja, dann ist dieses Buch für Sie geschrieben. Haben Sie mehr als die Hälfte der Fragen mit c) beantwortet, dann lachen Sie bitte nicht höhnisch, sondern gehen weiter und programmieren Linux-Kerneltreiber. Oder was Sie sonst so tun.
»I regularly have to google the basic syntax of a language I’ve used every day for 10 years. #coderconfessions«
—@HackerNewsOnion / Twitter, 10. Juli 2013
In den letzten Jahren wurde in Geek-Kreisen gern der »Dunning-Kruger-Effekt«[4] zitiert, demzufolge ausgerechnet inkompetente Personen besonders stark dazu neigen, das eigene Können zu überschätzen. Nachfolgestudien deuten darauf hin, dass es sich in Wirklichkeit anders und einfacher verhält: Menschen sind ganz allgemein nur schlecht in der Lage, ihre eigene Kompetenz auch nur halbwegs zutreffend einzuschätzen.
Ungeübte Programmierer schwanken zwischen Selbstüberschätzung und dem Glauben, zu dumm für das Metier zu sein. In der Begeisterung, zu der die Planung eines neuen Projekts führt, werden die eigenen Fähigkeiten oft überschätzt, insbesondere macht man sich keine Vorstellung davon, wie langsam die Entwicklung von funktionierendem Code tatsächlich voranschreitet. Die Konfrontation mit der unangenehmen Wahrheit führt dann entweder zu Verzweiflung (bei Projekten mit Deadline) oder Lustlosigkeit (bei Hobbyprojekten).
Selbstüberschätzung hat mehrere Ursachen. Zum einen lernt man als Anfänger ständig hinzu, das schmeichelt dem Ego. Die Lernkurve ist in den ersten zwölf Monaten, in denen man etwas Neues lernt, so steil, dass man nicht anders kann, als sich für einen ausgemachten Topchecker zu halten. Was schwer zu erkennen ist: Trotz des vielen und schnellen Dazulernens ist man gerade erst bis zu den Knöcheln ins Nichtschwimmerbecken gewatet. Die Welt der Programmierung ist für den Anfänger, um es mit Donald Rumsfeld zu sagen, voller »unknown unknowns«, also voller Wissenslücken, die man gar nicht als Lücken erkennt.
Eine weitere Ursache für Selbstüberschätzung liegt darin, dass unerfahrene Programmierer dazu neigen, nur die ersten 80 Prozent eines Projekts überhaupt zu erledigen, weil sie aufhören, sobald die Aufgabenstellung weniger interessant wird. Der 80-20-Regel[5] zufolge verursachen die dann noch folgenden 20 Prozent allerdings 80 Prozent der Arbeit. Man baut also mit einem Bruchteil der Programmierkenntnisse eines Profis eine Applikation zusammen, die »praktisch dasselbe« ist wie ihr Vorbild. Die dabei durch Unkenntnis und Fehlentscheidungen verursachten Probleme fallen nicht weiter auf, weil sie erst innerhalb der letzten 20 Prozent der Aufgabe ihre hässliche Fratze zeigen.
Überschätzung der eigenen Fähigkeiten oder Unterschätzung einer Aufgabe kann auch Vorteile haben. Wenn jeder von Anfang an über das Ausmaß seines Unwissens Bescheid wüsste, lebte die Menschheit vermutlich immer noch in Erdhöhlen (»Hochbau? Was man da alles wissen müsste!«). Auch bei einzelnen Projekten kann es hilfreich sein, sich zu verschätzen. Als Donald Knuth 1977 – frustriert über den hässlichen Textsatz des zweiten Bandes seines Hauptwerks »The Art of Computer Programming« – beschloss, selbst ein besseres Satzprogramm zu schreiben, rechnete er mit etwa sechs Monaten Entwicklungszeit. Das Ergebnis hieß TeX und war schon knapp zwölf Jahre später fertig. Der Doktorand George Bernard Dantzig erschien 1939 zu spät zu seinem Statistikkurs an der University of California und fand zwei Probleme an der Tafel vor, die er für Hausaufgaben hielt. Einige Tage später entschuldigte er sich bei seinem Professor, dass er so lange gebraucht habe, um die Aufgaben zu lösen; sie seien etwas schwieriger gewesen als sonst. Allerdings handelte es sich gar nicht um Hausaufgaben, sondern um bis dahin unbewiesene Statistiktheoreme, die Dantzig damit versehentlich bewiesen hatte. In manchen Fällen sind Fehleinschätzungen der Lage also durchaus hilfreich, weil sie einen davor bewahren, sich vom Umfang oder der Komplexität einer Aufgabe abschrecken zu lassen.
Auf der anderen Seite des Wetterhäuschens wohnt der Selbstzweifel. Der eigene Code ist ein hässliches, unwartbares Dickicht. Sicher müssen andere, bessere Programmierer nicht jeden Befehl vor jeder Verwendung in der Dokumentation nachschlagen. Niemand sonst vergisst über Nacht, was er sich beim Schreiben des Codes gedacht hat. Man ist einfach unbegabt und faul und wird zeitlebens ein schlechter Programmierer bleiben.
Die gute Nachricht: Den anderen geht es genauso. Auch erfahrene Programmierer sind vergesslich, unkonzentriert, arbeitsscheu und halten den eigenen Code für den schlechtesten der Welt. Es gibt nur wenige Probleme, die ausschließlich unerfahrene, halbherzige oder eilige Programmierer betreffen:
Unwartbarer Code
Code wird ohne Rücksicht auf spätere Wartbarkeit (durch einen selbst oder andere) geschrieben. Das liegt in erster Linie an mangelnder Erfahrung. Erst wenn man oft genug vor einem selbst erzeugten, undurchdringlichen Codedschungel gestanden hat, fällt es etwas leichter, beim Schreiben an den künftigen Leser zu denken. Nur ungewöhnlich phantasiebegabte oder zukunftsorientierte Programmierer erfassen diesen Sachverhalt gleich von Anfang an. Alle anderen müssen erst das Tal der Schmerzen durchschreiten.
Wahl ungünstiger Mittel
Wer nur eine halbe Programmiersprache oder Technik beherrscht, der wird sie zur Lösung sämtlicher Aufgaben heranziehen, die ihm einfallen. Oft ist das Problem dabei nicht totale Unkenntnis, sondern nur mangelnde Vertrautheit mit der nächstliegenden Herangehensweise.
Selbstüberschätzung
Auch gute Programmiererinnen überschätzen häufig ihre Produktivität. Das liegt zum einen daran, dass ihnen wie allen anderen Menschen die Fähigkeit zur realistischen Einschätzung fehlt, wie lange ein Projekt dauern wird. Zum anderen kristallisiert sich die eigentliche Problemstellung oft erst im Laufe der Arbeit heraus. Das ist bei schlechten Programmiererinnen nicht anders – nur um etwa drei Größenordnungen schlimmer.
Fehlendes Vorwissen
Jedes Konzept, dem der unerfahrene Programmierer begegnet, ist für ihn neu. Auch in der Softwareentwicklung gibt es jedoch relativ viele Ideen, die wieder und wieder in neuem Gewand Anwendung finden. Erfahrene Programmierer erkennen diese Muster, können sie benennen und tun sich dann leichter damit, sie in anderen Kontexten anzuwenden.
Der Perl-Erfinder Larry Wall nennt im Standardwerk »Programmieren mit Perl« Faulheit, Ungeduld und Selbstüberschätzung als wichtige Programmiertugenden. Faulheit ist gut, weil sie die Programmiererin dazu motiviert, so viel Energie wie möglich einzusparen. Sie wird arbeitssparende Software schreiben, das Geschriebene gründlich dokumentieren und eine FAQ verfassen, um nicht so viele Fragen dazu beantworten zu müssen. Ungeduld bringt die Programmiererin dazu, Software zu schreiben, die ihre Bedürfnisse nicht nur erfüllt, sondern vorausahnt. Und Selbstüberschätzung lässt sie auch das Unmögliche anpacken. Aber auch andere Untugenden können Programmierern, richtig eingesetzt, zum Vorteil gereichen:
Dummheit
»Mir kommt es oft so vor, als käme der schlimmste Spaghetticode von den Leuten, die am meisten gleichzeitig im Kopf behalten können. Anders bringt man solchen Code ja gar nicht zustande«, vermutet der Softwareentwickler Peter Seibel.[6] Ein weniger intelligenter Programmierer wird versuchen, eine möglichst einfache Lösung zu finden und dadurch mit höherer Wahrscheinlichkeit Code schreiben, den auch andere Menschen verstehen, warten und erweitern können.
Unwissenheit
Wissen um die Details einer Programmiersprache oder um abstraktere Konzepte ist eine feine Sache. Sobald es aber zu einem Paradigmenwechsel kommt – die Einführung der objektorientierten Programmierung war ein solcher –, werden viele bisher kompetente Programmierer durch ihr vorhandenes Wissen ausgebremst. Weitgehend ahnungslose Geschöpfe haben es in so einer Situation leichter, weil sie unvorbelastet an das Neue herangehen können.
Vergesslichkeit
Douglas Crockford, eine wichtige Figur in der Entwicklung von JavaScript, antwortet auf die Interviewfrage, ob Programmieren nur etwas für die Jugend sei: »Ich bin heute vielleicht ein bisschen besser als früher, weil ich gelernt habe, mich weniger auf mein Gedächtnis zu verlassen. Ich dokumentiere jetzt gründlicher, weil ich mir nicht mehr so sicher bin, dass ich nächste Woche noch weiß, warum ich etwas so und nicht anders gelöst habe.«[7] Außerdem wird ein Programmierer, der ständig Namen und Syntax der einfachsten Funktionen vergisst, stärker motiviert sein, sich eine Entwicklungsumgebung oder wenigstens einen Editor mit intelligenten Codevervollständigungsoptionen zuzulegen.
Fehlendes Durchhaltevermögen
Prokrastination
Ekel vor dem eigenen Code
Ehrgeizlosigkeit
Trägheit
[8]
Der selbst geschriebene Code sieht womöglich aus wie im Kinderbuch: »Das ist der Hund. Der Hund spielt im Garten. Jetzt bellt der Hund.« Aber das ist kein Grund zur Demut. Nicht die Fähigkeit, möglichst komplexen Code zu schreiben, zeichnet gute Programmierer aus. Elegante und gute Ideen lassen sich auch in schlichtem Code ausdrücken, und umgekehrt kann sich hinter kompetentem Code ein schlecht durchdachtes Konzept verbergen.[9]
Häufig sind die Aufgaben, mit denen man als Programmierer zu tun hat, auch gar nicht so kompliziert wie zunächst gedacht. Bernie Cosell, einer der Programmierer hinter dem Ur-Internet Arpanet, erklärt: »Ich habe ein paar Grundregeln, die ich den Leuten beizubringen versuche. Das sind meistens Leute, die direkt vom College kommen und glauben, sie wüssten alles über Programmierung. Zum einen geht es mir dabei um die Einsicht, dass es nur ganz wenige an sich schwierige Programmierprobleme gibt. Wenn man Code betrachtet, der sehr schwierig aussieht – wenn man überhaupt nicht versteht, was das alles soll –, dann ist das fast immer ein Anzeichen dafür, dass dieser Code schlecht durchdacht ist. Dann krempelt man nicht die Ärmel hoch und versucht, den Code geradezuziehen, sondern man lehnt sich erst mal zurück und denkt nach. Wenn man lange genug nachgedacht hat, stellt sich heraus, dass alles ganz einfach ist. (...) Ich bin lange genug im Geschäft; ich weiß, dass es ein paar sehr komplexe Probleme gibt. Aber das sind nicht viele. Es ist immer wieder dasselbe: Wenn man gründlicher darüber nachdenkt, wird es einfacher, und die eigentliche Programmierung ist dann am Ende ganz leicht.«[10]
4.
5.
6
7
8en.wikipedia.org/wiki/Global_variables
9
10