(Anm.: Wil Shipley ist der Autor von Delicious Library, mit welcher man seine Sammlung aus Bücher, CDs, Filmen, etc. einfach verwalten kann. Im Moment arbeitet er an Delicious Library 2 - die erste Mac-Anwendung die bereits als Beta-Software einen Apple Design Award gewonnen hat. In seinem Blog Call me Fishmeal gibt er ganz gern Ratschläge für Programmierer. Einer davon ist Free Programming Tips are Worth Every Penny, der auch für nicht-Mac-Programmierer sehr interessant ist. Übersetzt mit freundlicher Erlaubnis von Wil.)
Manchmal meint jemand zu mir, “Hey, Wil, du programmierst doch seit die Dinosaurier die Erde beherrschten… hast du nicht ein paar Ratschläge für uns Jungspunde?”
Worauf ich immer antworte, “Hey, ihr Schlingel, RUNTER VON MEINEM RASEN!”
Nein, nein, normalerweise wende ich zögernd “Ach, ich weiss doch auch nicht so recht” ein, während ich schüchtern auf meine Füße starre.
Aber ich hab in letzter Zeit oft darüber nachgedacht, nachdem ich zuerst alleine so viel Code für Delicious Library geschrieben habe (zum ersten mal seit vielen Jahren), und dann einen neuen Programmierer eingestellt und versucht habe ihm mein Wissen zu vermitteln. Und dabei habe ich einen Stil entwickelt:
Nun, ich weiss natürlich nicht viel über echte Samurai, aber was ich so von ihnen gehört habe, stehen sie sich stundenlang gegenüber und starren sich an, bis einer plötzlich BAM zuschlägt, und der andere ist am Boden.
So solltest du deinen Code schreiben.
Zuerst nachdenken. Dann noch mehr nachdenken. Denk über das Problem als Ganzes nach. Denk an den kleinen Teil des Problems mit dem du anfangen willst. Denk nochmals über das ganze Ding nach, in Relation zu deinem geplanten Startpunkt.
Schreib keinen Code solange du nicht weisst was du machen willst. Natürlich kannst du allein durch nachdenken nicht immer sofort wissen was du machen willst, weshalb du ein TEST-Projekt anlegen und einen Haufen hässlichen Code schreiben solltest, um sicherzustellen das deine Ideen korrekt sind.
Dann, fang nochmals an, in einem neuem Verzeichnis. Wir hatten so um die sieben verschiedene Testprojekte während der Entwicklung von Delicious Library – einen für den Video Barcode Leser, einen für den Laden, einen für das Parsen von Amazons XML, einen um mit Bluetooth-Scannern zu kommunizieren, und so weiter. Wir haben gelernt wie wir ein Problem lösen können bevor wir das Hauptprojekt mit Code verschandelt haben.
Dann haben wir die brauchbaren Teile aus den Test-Projekten kopiert, und den überflüssigen Code weggeworfen. Das bringt uns zu Regel #2…
Schreib all deinen Code sauber, schon beim ersten mal. Mach Klassen für alles. Verwende Enumerationen. Nimm keine Abkürzungen. Kein Teil von deinem Code soll jemals sagen “Oh, das richte ich später her.” Du wirst es später NICHT herrichten. Ernsthaft, wie oft sagst du zu dir “Heute werd ich mich in dieses hässliche Stück Code einarbeiten und ihn schön und sauber machen, ohne neue Funktionalität hinzuzufügen?” Niemand zahlt für so was. Ich wurde sogar mal zum Chef zitiert weil ich während eines bedeutenden Update für ein Stück Software bei einem vorherigem Job ein Stück Code aufgeräumt habe – “Wieso vergeudest du deine Zeit mit dem modifizieren von existierendem Code der schon funktioniert? Füg einfach deine neuen Features hinzu und lass es sein.” Was solls das ich den Code nicht verstehen konnte, oder das sauberer Code stabiler, wartbarer, erweiterbarer Code ist?
Kehre nichts unter den Teppich. Schreib jede Zeile so dass sie kugelsicher ist. Schreib jede Methode so als ob jede andere Methode nur versuchen würde sie zum Absturz zu bringen, und dein Job ist es sicherzustellen dass es nicht in DEINEM Code passiert. Nimm an dass der User zufällig auf irgendwelche Tasten drückt. Nimm an dass das Netzwerk auf einmal nicht verfügbar ist. Nimm an dass die Hardware versagen wird.
Erkläre deine Routinen laut. Sobald du merkst dass du “Nun, das ist nicht komplett korrekt, aber es geht weil ich zu diesem Zeitpunkt weiss dass…” sagst, HÖR AUF. Mach es noch mal neu. Schreib es korrekt.
Und, jedes mal wenn du in einem Stück Code bist weil du ihn erweitern oder einen Bug beheben musst, RÄUM IHN AUF. Räum ihn auf während du dahin arbeitest, jedes mal. Mach aus diesen Konstanten eine Enumeration, wie du schon immer machen wolltest. Nimm diese hartkodierten Strings und mach aus ihnen Klassenvariablen. Ersetze englische Phrasen durch NSLocalized-Varianten. Immer aufräumen.
Weniger Sourcecode ist besser. Das ist beinahe immer wahr. Die Ausnahmen zu dieser Regel sind so selten dass du jedes mal RICHTIG an dir zweifeln solltest wenn du glaubst eine gefunden zu haben. Weniger Sourcecode-Zeilen bedeuten fast immer weniger Code den ein neuer Programmierer verstehen muss wenn er zu einem Projekt dazukommt. Es bedeutet dass du dich im Jahr darauf an weniger Zeug erinnern musst wenn du mitten in einer anderen Version steckst. Es bedeutet weniger Orte an denen du dich vertippen kannst. Es bedeutet weniger Anweisungen die ausgeführt werden müssen. Es bedeutet dass weniger geändert werden muss wenn du das Programm umstrukturierst.
Daraus kann man ein paar interessante Schlussfolgerungen ziehen. Wenn du zum Beispiel eine Klasse schreibst um ein Stück Text in Rot anzuzeigen (warum auch immer), füg nicht zwecks Zukunftssicherheit ein paar Methoden ein die es dir erlauben den Text in Blau oder Grün oder Purpur zu zeichnen. Das ist nämlich mehr Code als du im Moment brauchst, und “weniger Code ist besser.”
Aber falls du plötzlich draufkommst dass du purpurnen Text zeichnen musst, könntest du natürlich den roten Code kopieren, nur diesmal eben mit Purpur. Aber, “weniger Code ist besser,” weshalb du den Code zum Zeichnen des Textes abstrahierst und ihm einen Farb-Parameter übergibst, damit du den gleichen Code wieder verwenden kannst.
Ich will darauf hinaus dass Code nicht verallgemeinert werden sollte solange er nicht an mehreren Stellen benötigt wird. Die schlimmsten Bibliotheken sind diejenigen die geschrieben werden obwohl sie nie dazu verwendet werden tatsächlich Arbeit für den User zu erledigen.
Und schreib keinen längeren, schwerer zu verstehenden Code weil du glaubst dass er schneller ist. Vergiss nicht dass Hardware schneller wird. VIEL schneller, jedes Jahr. Aber Code muss von Programmierern gewartet werden, und gute Programmierer sind knapp. Wenn ich also ein Programm schreibe das unglaublich wartbar und erweiterbar ist, und es ist etwas zu langsam, dann hab ich eben für nächstes Jahr einen Schlager parat. Und das Jahr darauf, und das Jahr darauf.
Wenn du jetzt längeren Code schreibst damit er jetzt schnell ist, dann hast du jetzt einen Schlager parat. Und nächstes Jahr hast du einen grossen Haufen unwartbaren Code, und du wirst länger brauchen neuen Features hinzuzufügen und Bugs zu beheben, und dann kommt jemand anderer daher und lässt dich einfach links liegen.
Ich will damit nicht sagen das langsamer Code gut ist. Es gibt eine Zeit und einen Ort für Optimierungen…
Diese Zeit und dieser Ort sind NACHDEM DU FERTIG BIST. Optimiere Methoden NUR nachdem du sichergestellt hast dass sie richtig funktionieren und kugelsicher sind UND du sie in Shark durchgetestet hast und draufgekommen bist dass die Methode kritisch ist (Anm.: Shark ist ein Profiling-Tool für Mac OS X).
Optimiere nicht während du deinen Code schreibst. Warum nicht? Weil du aller Wahrscheinlichkeit nach deine Zeit vergeudest. Der Großteil des Code den Programmierer optimieren wird so selten ausgeführt dass der Unterschied nur in Nanosekunden gemessen werden kann. Ausserdem bist du wahrscheinlich auch nicht sehr gut im Optimieren. Nicht böse sein, aber Maschinen und Bibliotheken sind komplexe Systeme, und deine Vermutung was da langsam ist sind wahrscheinlich eher ungenau. Du benötigst Testtools um herauszufinden was WIRKLICH langsam ist. Die Resultate sind oft überraschend. (Zum Beispie ist in Mac OS 10.3 das Entfernen und Hinzufügen einer View mit vielen Tooltips extrem langsam wenn es oft stattfindet. Es ist unmöglich so was zu wissen ohne es vorher in Shark getestet zu haben.)
Das nächste mal wenn du versucht bist ein Stück Code unlesbarer aber dafür schneller zu machen, frag dich “Wie oft wird das WIRKLICH aufgerufen?” Ist die Antwort weniger als hundert mal pro Sekunde? Prozessoren können mittlerweile MILLIARDEN Operationen pro Sekunde abarbeiten.
Zugegeben, Delicious Library ist nicht das schnellste Programm in der Welt, aber es ist um EINIGES schneller als es am Anfang war. Diese grossen, wunderschönen Hüllen verschlingen einiges an Speicher. Als wir die Library zum ersten mal schrieben und du mehr als um die 400 Artikel geladen hast, haben die Hüllen den ganzen Hauptspeicher belegt und das Programm ist einfach dahingekrochen. (Es war wie iPhoto 1.)
Ich habe das ganze Hüllen-Caching und -Kombinations-System neu designed, und es so schnell hinbekommen dass es bequem mehrere tausend Artikel verwalten kann, und, wenn du den Tabellenmodus verwendest, sogar mehrere zehntausend (Ich hatte niemals so viele Artikel). Das hat mehrere Wochen gekostet. Ich bin nicht so schnell wie iPhoto 4, aber ich bin ziemlich nah an der Performance von iPhoto 2 dran, und wenn man bedenkt dass ich das alleine gemacht habe und das Delicious Library 1 war, bin ich ziemlich stolz darauf.
Was ist die Moral des ganzen? Wenn ich Zeit damit verbracht hätte andere Teile des Programms zu optimieren während ich sie schrieb, hätte ich am Ende nie diese Wochen zur Verfügung gehabt um die Bildverarbeitung herzurichten, den langsamsten Teil des Ganzen. Ich hätte ein Programm veröffentlichen müssen dass vielleicht gerade mal ein paar hundert Artikel verwalten kann, und hätte gleich einen Patch dafür schreiben müssen sobald die Leute zum schreien angefangen hätten.
Kommentar schreiben
Kommentare
Danke, eine sehr gute Übersetzung und ein interessanter Artikel ist das!
Danke. Falls solche Artikel-Übersetzungen auf Anklang stossen, werd ich das in Zukunft öfters machen (Also Artikel wo es nicht unbedingt um Ruby, sondern allgemein ums Programmieren geht).
Finde die Übersetzung auch sehr gut gelungen! Looking for more (-: