Im Artikel „Was machen Informatiker (bzw. Softwareentwickler im Speziellen) eigentlich so?“ habe ich abstrakt-grob beschrieben, was wir Softwareentwickler so machen. Dabei habe ich angedeutet, dass es sich dabei nicht nur um eine mathematisch-theoretische Wissenschaft handelt, sondern es auch eine Art Ingenieurdisziplin mit handwerklichen, (manche sagen auch künstlerischen) Komponenten, die man ganz praktisch erlernen muss, ist. In diesem Artikel geht es nun um Vorgehensweisen und Werkzeuge, die man nutzen kann, um sich und anderen (also Kunden, Kollegen, Nachfolgern usw.) bei größeren Projekten das Leben langfristig leichter und spaßiger zu machen, und in weniger Zeit ein besseres (fehlerfreier, wartbarer, benutzbarer, erweiterbarer, sauberer, schöner, erfolgreicher) Endprodukt hervorbringen kann, unter das man dann auch gerne seinen Namen schreibt. Das Folgende ist vermutlich also nur für Leute, die selbst programmieren, interessant, aber ich habe Lust, das mal alles irgendwo hinzuschreiben.
Die Nützlichkeit der Ratschläge in diesem Artikel sind größtenteils nicht empirisch belegt sondern mehr Gefühl, subjektive Erfahrung und von anderen gelernt. Trotzdem haben sie sich natürlich meines unheimlich kritischen persönlichen Urteils zu unterziehen gehabt. 😉
Ebenfalls sind sie weder vollständig noch allgemeingültig oder ausführlich (dafür aber oft weiterführend verlinkt). Es sind nur Hinweise, die man im Informatik-Studium nicht unbedingt mitbekommt, und Dinge, die man sich mal genauer angucken kann, und die einem dann unter Umständen helfen könnten. Mir tun sie es zumindest oft, auch wenn ich mich selbst noch zu häufig nicht daran halte. Aber ich lerne ja auch noch dazu; hoffe ich zumindest. 😀
Ich habe den Eindruck, dass man normalerweise in Tätigkeiten (Beruf, Hobby, was auch immer) nur wirklich gut werden kann, wenn man sie auch gerne macht. Vielleicht funktioniert es aber auch umgekehrt, also dass man sie lieber macht wenn man merkt, dass man sich stetig verbessert und dadurch Schönheit in den Ergebnissen seiner Arbeit sieht. Also, benutz deine Metakognition und erkenne deine Stärken und Schwächen und arbeite an beidem. Werde dabei zum Hansdampf in allen Gassen. Dabei hilft nicht nur reines Nachdenken, sondern auch (Hör-)Bücher, Vorlesungen, Diskussionen etc., denn obwohl man zwar viele gute Ideen selbst haben kann, kann man doch nicht alle alleine haben. Man muss keine haushohen Zeitschriftenstapel haben, die man alle gelesen hat. Oft ist ein Buch über Grundlagen (die bleiben nämlich) wirklich verstanden zu haben eh viel besser als von tausend verschiedenen Trends oberflächlich gehört zu haben.
Aber auch hier sollte man beim Lesen kritisch bleiben. Manche Bücher (und auch Blogs ^_-) sind einfach Mist, und es gibt keinen Grund, sich dann zu zwingen, die trotzdem zuende zu lesen.
Wenn man sich aber jahrelang regelmäßig mit unterschiedlichen Themen beschäftigt, kann da schon einiges zusammen kommen. Die Regelmäßigkeit kann man unter anderem gut hinbekommen, wenn man beispielsweise die Zeit im Auto/Zug für Hörbücher oder Tonspuren von Vorlesungen nutzt. Ansonsten kann man aber auch einfach mal herumprobieren, welche Lernform einem liegt (Vorlesungen beim Crosstrainern gucken anyone? :-))
Zusätzlich ist es aber gut, auch etwas von der aktiven Kultur mitzubekommen. Dafür gibt es sicher viele gute Anlaufstellen. Ich persönlich mag momentan /r/programming gerne. Auch finde ich es nett, aktiv in einer Community mitzumachen, also auch selbst Fragen zu beantworten wenn man etwas weiß. Hier bietet sich beispielsweise stackoverflow an. Aus den sich ergebenden Diskussionen kann man ebenfalls lernen. Achja, falls es dich abschreckt, dass die Links auf englischsprachige Webseiten zeigen, ändere das, also nicht die Links sondern die Tatsache, dass sie dich gruseln. Um Englisch (zumindest lesen können) kommt man eigentlich eh nicht wirklich herum.
OK, also erstmal ein paar allgemeine, teilweise banale, und nicht nur für Softwareentwickler relevante Tipps:
Wenn du eine Frage hast, google sie; auch wenn du denkst, dass das Problem eigentlich t zu den andezu spezifisch ist. Man ist manchmal überrascht wieviele Leute, doch schon das gleiche Problem hatten. Und ich bin überrascht, wie oft trotzdem nicht einfach mal im Netz gesucht wird.
Ebenfalls gucke ich manchmal vermutlich ziemlich doof wenn ich sehe, was für ein Chaos Entwickler auf ihrem Rechner haben. Ich bin alles andere als ein Ordnungsfanatiker, aber wenn die Produktivität (und man selbst, und irgendwann bestimmt auch ein anderer) leidet, nur weil man zu faul ist, mal eben ein Bischen aufzuräumen, finde ich das schon schade. (Ja, man kann Emails tatsächlich automatisch filtern und sortieren lassen. Achja, und schalte die Thread-Ansicht deines Clients an! ;-))
Wenn sich eine Aufgabe ergibt, die du irgendwann erledigen willst, schreib sie (elektronisch) auf. (Für Bugs usw. bietet sich Issue-Tracking an.) Egal ob sie dir gerade in einem Meeting zugekommen ist oder bei irgendwas anderem selbst eingefallen ist. Halte dir den Kopf für das Suchen nach innovativen Lösungen frei, und müll ihn nicht mit dem Auswendiglernen irgendwelcher temporären Daten zu. Und denk beim Sortieren deiner Todo-Liste daran, dass Dringlichkeit und Wichtigkeit zwei verschiedene Dinge sind.
Falls man Teil eines Prozesses ist, der sich irgendwie ineffizient anfühlt, kann man auch ruhig mal nachfragen, warum das so ist. Dabei sollte man aber nicht das Gefühl vermitteln, dass alle anderen doof sind, und man selbst der große Erlöser ist, sondern erstmal wirklich nur verstehen wollen, wie das ganze zu Stande kommt. Über Möglichkeiten, wie man soetwas geschickter formulieren kann, gibt es ebenfalls viel Literatur.
Wenn man dann irgendwann mit einem Verbesserungsvorschlag (oder sonstigem) daherkommt, gilt es auch immer zu beachten, welche Aspekte für die jeweilige Zielperson wichtig sind. Ein BWLer interessiert sich vermutlich mehr für finanzielle Zahlen, der Techniker für gute Wartbarkeit und der Theoretiker für abstrakte Schönheit, wobei es aber nicht nur auf die firmeninterne Position sondern auch auf die Persönlichkeit usw. ankommt.
In jedem Fall gilt es, den richtigen Moment abzuwarten. Im Zweifelsfall kann man auch einfach fragen, ob der andere gerade Zeit hat oder lieber ein anderes Mal (Termin ausmachen) darüber reden möchte.
Wer möchte, dass ihm zugehört wird, sollte aber ebenfalls mal seine Kollegen (gerne auch aus anderen Bereichen) die Chance geben, zu erzählen, was sie beschäftigt, und dabei aktiv zuhören.
Wenn es im (Großraum-) Büro allerdings mal zu laut wird, kann man sich zwischendurch immernoch mit (gut isolierenden) Kopfhörern und netter (eventuell instrumentaler) Musik vor zu vielen Unterbrechungen schützen; aber auch nicht 24/7, weil man ja schon manchmal noch mitbekommen sollte, was so um einen rum abgeht.
Oh, und nicht zu viel multitasken (also im Kopf, nicht im Computer), und auch mal ein kreatives Päuschen einlegen.
Man ist ja erwachsen und für sich selbst verantwortlich (wie eventuell für das Backup seiner Daten). Und wenn man mal etwas falsch gemacht hat kann man das normalerweise ruhig eingestehen. Die Hauptsache ist, dass man es korrigiert und etwas daraus lernt und das möglicherweise auch nach außen hin signalisiert. Oft kommt das nämlich sogar gut an. „Hey Chef, müsste ich jetzt nicht mehr Geld bekommen, nachdem ich hierdrin besser geworden bin? ;-)“
Ein unbeliebtes Thema bei vielen Entwicklern sind Aufwandsschätzungen. Softwareentwicklung ist ein kreativer Prozess, dessen Verlauf sich nicht einfach vorhersagen lässt. Es sollte auch zwischen zwei verschiedenen Arten der Schätzung unterschieden werden. Wenn festgelegt werden muss, wann ein Projekt spätestens abgeschlossen ist (Deadline), muss man natürlich so Planen, dass das auch sicher klappt. Wenn aber nur eine Entscheidung getroffen werden muss, ob es sich lohnt, ein Projekt überhaupt anzugehen, sollte man seine Ehre beiseite lassen können, und sich nicht bemühen, immer länger zu schätzen als man vermutlich tatsächlich braucht, sondern im Durchschnitt richtig zu liegen. Ja, das bedeutet, dass man dann auch mal länger braucht als gedacht. Das lässt sich bei kleinen Projekten (auch wenn es da nicht gefordert ist) gut üben. Zusätzliche Unsicherheitsfaktoren können ruhig mit angegeben werden, und wenn man nach einer Schätzung gefragt wird, braucht man sich nicht genötigt fühlen, sofort eine Zahl in Manntagen/wochen/monaten anzugeben, sondern sollte darum bitten, etwas Zeit zum Analysieren zu bekommen, um dann nachher besser antworten zu können.
So, nun zu den spezifischeren Punkten. Zunächst einmal sollte man sich damit abfinden, dass man keine perfekte/fehlerfreie Software schreibt. Fehler sind zwar ärgerlich, aber bei größeren Projekten zwangsläufig vorhanden. Je nach Aufgabe sind die Anforderungen auch unterschiedlich. Schreibe ich Software, mit der Astronauten ins All befördert werden sollen, oder geht es um ein Weltraumballerspiel, oder nur um einen Einmal-Wegwerf-Parser für irgendwelche speziellen Logs? Risiko, Nutzen und Aufwand müssen abgewogen werden. Wenn du dazu neigst, eher zu viel vorm Handeln nachzudenken, sieh zu, dass dich das nicht davon abhält, überhaupt irgendwann loszulegen. Wenn du eher einfach wild drauflos (und dann gegen Wände) rennst, denk zunächst etwas mehr nach. Hierfür muss man lernen, sich selbst einzuschätzen. Als grobe Richtlinie kann man sich merken: Mache dir Gedanken, aus welchen Subsystemen der Prozess, den du darstellen willst, besteht, und welche Daten von zwischen ihnen fließen, aber häng dich nicht an den Funktionssignaturen einzelner Methoden und ähnlichem auf. Die tatsächliche Implementierung macht man im Zweifelsfall dann aber meistens besser direkt ordentlich, denn oft ist man überrascht, wie oft man den Code dann später doch tatsächlich nochmal benutzen oder verändern will, und dann beißt die Frickelei einen schnell man in den Hintern.
Die IT-Welt entwickelt sich schnell weiter, und manche Dinge/Software benutzt man nur, weil man zufällig als erstes mit dieser in Kontakt kam. Deshalb sollte man ruhig zwischendurch neue Sachen (zb. Betriebssysteme) ausprobieren. Damit man seinen Arbeitsrechner damit nicht zumüllt bietet sich zb. Virtualbox an. Falls Windows dir auf den Nerv geht, probier ruhig mal Linux aus. 😉
Leistungsfähige Hardware zu haben ist wichtig. Es muss kein wassergekühlter high-end-gaming-PC sein, aber wenn man ständig darauf wartet, dass irgendwelche Programme starten oder der Compiler ewig braucht, nervt das nicht nur, sondern kostet auch Zeit, und für viele von uns somit auch Geld. Ebenfalls kann ein zweiter Monitor hilfreich sein.
Das praktischte Datenformat ist immernoch plain text. Einige der Vorteile davon sind, dass man die Unix-Tools (gibt es auch für Windoof) benutzen, und beliebig mit regulären Ausdrücken (lernen!) drauf herumwuseln kann, gerne auch mit batch/bash-scipts. Oft ist man in der Konsole mit sowas wesentlich schneller als mit GUI-Rumgeklicke.Ein wichtiges Werkzeug ist natürlich ein guter Texteditor (Nein, das normale Windows-Notepad zählt nicht dazu. ;)). Also probiere verschiedene Editoren aus, such dir einen aus, und lerne ihn gut zu bedienen. Für mich ist das momentan Sublime, aber auch Notepad++ (Windows only) und viele andere sind gut. Leute, deren Bärte lang genug sind, kommen vielleicht sogar mit Vim oder Emacs super klar. 😉
Aber auch für die „normalen“ Editoren gilt: Lern die Tastenkombinationen (und generell Tippen ohne Hingucken, sowie Text nur mit Tastenkombinationen umzuformen). Jedes mal wenn du die Maus anfasst, verschenkst du Zeit, machst Fehler, nimmst eine schlechte Körperhaltung an und siehst uncool aus. Aber auch außerhalb deines Editor / deiner IDE solltest du mit möglichst wenig Mauskontakt klarkommen. Das zu lernen ist zwar anfangs anstregend, aber es lohnt sich, denn nicht nur die Geschwindigkeit deiner Arbeit, sondern sogar die Qualität kann dadurch steigen, weil du durch „kürzere Wege“ andere/bessere Mikroentscheidungen triffst.
Wenn man an einem Projekt arbeitet, sollte man sich einen Style (Einrückung, Namenskonventionen usw.) innerhalb dieses Projekts beibehalten.
Superhilfreich sind Versionsverwaltungssysteme wie zB. Git. Etwas in dieser Art sollte man in jedem Fall benutzen, nicht nur weil man beliebig „undo“ sagen kann, sondern auch weil man Code nicht auskommentieren muss sondern einfach rauswerfen kann (alte Versionen sind ja weiterhin verfügbar), und weil man aber gute Tutorials im Netz, einfach googeln. Man kann alles undo-en, muss keinen auskommentierten Code mitrumschleppen, und kann immer gucken, in welcher Version was (und was fürn Bug) reingekommen ist, und bei Teams wers war und warum.
Es gibt seehr viele verschiedene Programmiersprachen. Man muss aber nichtmal alle sprechen können, die auf LangPop oder TIOBE auftauchen. Allerdings ist es meistens eine gute Idee, über den Tellerrand hinauszuschauen. Wenn man aber beispielsweise schon Ruby kann, muss man sich nicht noch (außer natürlich ein Projekt verlangt es) mit Python, Lua oder anderen interpretierten, dynamisch typisierten garbadge-collectenden Sprachen beschäftigen, sondern lieber mit Sprachen, die andere Paradigmen benutzen oder auf anderen Abstraktionsebenen arbeiten. Für den erwähnten Ruby-Fall wäre vielleicht etwas statisch typisiertes, compiliertes wie C oder C++ und etwas möglichst rein funktionales wie Haskell oder Scheme toll. Gerade letzte Kategorie kann Programmierern, die es gewöhnt sind imperativ zu denken, zunächst sehr schwer fallen. Das Umdenken lohnt sich aber, auch wenn man die Sprache nie produktiv einsetzt, da es das generelle Verständnis für Algorithmen verbessert und auch den Programmierstil in imperativen Sprachen positiv beeinflussen kann. Statt Spaghetti produziert man dann vielleicht wirklich mal Ravioli. 😉 Wenn man normalerweise eher low-level programmiert, kann es eine gute Erfahrung sein, sich mal mit Webzeugs zu beschäftigen. Je größer das persönliche Repertoire ist, desto geringer ist die Chance, dass man eine Sprache wählt, die für das jeweilige Projekt vielleicht eigentlich eher ungeeignet ist. Eventuell kombiniert man auch mehrere Sprachen miteinander und implementiert die wenigen performancekritischen Ecken eines Python-Programms dann in C. Sprachen sind Werkzeuge und je nach Problemstellung unterschiedlich geeignet. Es sollte einem also nicht passieren, dass alles wie ein Nagel aussieht, nur weil man nichts als einen Hammer zur Verfügung hat. 🙂
Programs must be written for people to read, and only incidentally for machines to execute.
– Structure and Interpretation of Computer Programs
Etwas, dass es grundsätzlich zu beachten gibt, ist, dass man sich nicht wiederholen (DRY) sollte. Wenn eine eigentlich einfache Systemänderung nämlich fordert, dass man direkt an mehreren Stellen etwas tun muss, ist die Frage nicht, ob man das jemals vergisst, sondern wann man das vergisst. Bei Backups ist Redundanz toll, in der Softwareentwicklung hingegen tötlich. Falls Duplikation sich gar nicht vermeiden lässt, sollte man diesen Vorgang im Build-Prozess automatisieren. Nur in ganz seltenen Fällen, wie zb. in C++ bei den Funktionssignaturen in den Deklararionen einer .hpp-Datei und den Definitionen in der zugehören .cpp-Datei lässt es sich nicht vermeiden. Aber hier macht einen der Compiler glücklicherweise auf die meisten Fehler aufmerksam.
Dass falsche bzw. veraltete Informationen schlimmer sind als gar keine, gilt selbstverständlich auch für Kommentare. Da man meistens mehr Zeit damit verbringt, Code zu lesen, zu verstehen und zu verbessern, als damit, neuen zu schreiben, können Kommentare wichtig sein. Jedoch sollten sie nicht so sehr erklären was oder wie der Code etwas tut, sondern mehr warum er etwas tut. Wenn er so klar geschrieben werden kann, dass Kommentare überflüssig sind, ist das aber natürlich noch besser. Für Interfaces-Dokus bieten sich Doxygen, Docstring usw. an. Wenn die Klasse oder das Modul oder was auch immer man gerade kommentiert, nicht thread-safe ist (warum eigentlich), sollte man das auch irgendwo angeben, ebenso wie eventuell geworfene Exceptions. Generell sollte sie den Benutzer, also den Entwickler einer aufrufenden Funktion, oft auch man selbst, mit ihrem Verhalten nicht überraschen. Falls die gewählte Programmiersprache Design by contract unterstützt (oder es sich wie in Python mit decorators umsetzen lässt), kann es auch helfen, das zu nutzen. Ansonsten sollte man preconditions einer Funktion zumindest mit Assertions absichern, um eventuelles undefiniertes Verhalten auf jeden Fall zu verhindern. Wenn die Funktion nicht gerade performancekritisch ist (was nur die wenigsten sind), kann man die Assertions auch ruhig im Release aktiviert lassen (crash ist besser als trash).
Orthogonalität ist ein wichtiges Konzept. Eine Komponente sollte nur eine Sache ordentlich machen (unix philosophy), sodass man bei einer veränderten Anforderung auch möglichst nur diese eine Komponente verändern und nicht an tausend Ecken dran muss. Wenn man Angst hat, etwas zu ändern, weil das System dadurch irgendwo ganz anders scheppern könnte, ist etwas faul. Daraus ergibt sich, dass man Gemeinsamkeiten von Klassen/Funktionen heraus-refactoren sollte. Wenn man die Chance hat, eine Funktion pure functional zu schreiben, also dass ihr Ergebnis nur von den übergebenen Parametern und nicht von irgendwelchem externen state abhängt, sollte man das ebenso tun. Das vermeidet Fehler und macht das Testen einfacher.
Arbeitskollegen sollten zwar voneinander wissen, was der andere tut. Für Software-Komponenten gilt das aber nicht. Jedes Teil sollte nur mit seinen direkten Nachbarn reden, und da auch nur so viel wie nötig, wobei immer nur die abstrakte Schnittstelle interessiert und Implementationsdetails egal sind. So macht man sich seine Abstraktionslayer auch nicht kaputt und hält die Kopplung lose.. Manchmal bekommt man auf der höchsten Ebene dann fast automatisch soetwas wie eine DSL geschenkt, was den Vorteil hat, dass man business errors schnell von Fehlern „weiter unten“ unterscheiden kann. Speziell bei der objektorientierten Programmierung sollte man dann noch mit soetwas wie Kapselung, „Tell, don’t ask.“ und das Liskov substitution principle kennen. So bleibt die Software einfach und offen für Erweiterungen ohne dass man schon von Anfang an Sachen schreiben muss, die man vermutlich eh nie brauchen wird. Manche Dinge sind nämlich nicht perfekt wenn man nichts mehr hinzufügen kann, sondern wenn man nichts mehr weglassen kann. 🙂
Design patterns, MVC usw. sollte man kennen und anwenden können, aber nicht darauf beharren wenn sie unpraktisch sind. Ähnlich wie UML sind sie Möglichkeiten, seinen Code besser Kommunizieren zu können, aber nicht dafür, ihn vollkommen zu bestimmen, denn die Implementierung ist einfach kein komplett im Voraus planbarer mechanischer Prozess, sondern ein Vorgang, bei dem man fast minütlich kleine Entscheidungen treffen muss. Einige Methoden berücksichtigen das auch.
Mit der Zeit entwickelt man ein Gefühl dafür, ob an einem Code irgendetwas faul ist und man nochmal kritisch drübergucken sollte. Ein Beispiel für solche code smells sind hardcodierte Werte. Sowas sollte man stattdessen vernünftig benennen und von außen konfigurierbar machen. Und wenn man gerade schonmal da ist, kann man versuchen, ganz in alter Pfadfindermanier, den Code sauberer zu hinterlassen als man ihn vorgefunden hat. Denn wenn man Mist hinterlässt, stellt sich schnell der Broken-window-Effekt ein.
Eine gewisse Art Faulheit ist allerdings gut, denn wenn man stupide Tätigkeiten dadurch lieber automatisiert, spart man sich viel Zeit. Tests sind hierfür ein gutes Beispiel. Diese kann man oft gut mit make, bash, oder Scriptsprachen wie Perl oder Python automatisieren und eventuell sogar schon welche schreiben, bevor man anfängt, das eigentliche Produkt, dass man testen möchte, zu entwickeln. Aber auch wenn dann alle Tests bestanden werden, bedeutet, das nicht, dass die Software fehlerfrei ist, denn man deckt fast nie alle Fälle ab. Wenn dann ein Bug gemeldet wird, und man ihn reproduzieren konnte, muss man halt klassisch Debuggen. Dafür sollte man lernen, einen Debugger zu benutzen. Damit kommt man besser voran als durch wildes Einstreuen vieler Print-Statements. Wenn der Bug dann behoben ist, kann ein entsprechender Testfall direkt zu den anderen aufgenommen werden.
Falls man selbst (incl. rubber duck debugging) bei der Fehlersuche nicht weiterkommt, kann man noch in einer entsprechenden Community nachfragen. Das Formulieren der Frage und vorallem das Reduzieren des Codes auf den problematischen Teil reicht manchmal dann schon, damit man doch selbst drauf kommt. Grundsätzlich gilt es dabei zu bedenken, dass der Fehler meistens im eigenen Code liegt und eher selten in viel benutzen Libraries und noch seltener im Compiler/Interpreter. Bei der Auswahl der Bibliotheken und sonstiger Tools ist es vorteilhaft, sich im Zweifelsfall aus bekannten Gründen auf freie Software zu konzentrieren, und möglichst schlanke Libs zu wählen. Das Rad hingegen selbst neu erfinden sollte man nur zu Übungszwecken, denn oft wird es zunächst nämlich eher quadratisch. 😉
Wenn irgendeine Funktionalität noch nicht vorhanden ist, oder man unabhängig von ihr testen können will, kann ein Mock dafür hilfreich sein. Auch für Präsentationen, zum Umgehen von blocking points und für Prototypen sind diese nützlich. Mit letzten kann man den Kunden schon in die Entwicklung einbinden und schnelles Feedback bekommen. Wenn es eh Wegwerfcode wird, kann man ihn auch in einer anderen Sprache als Endprodukt entwickeln, und muss nicht so viel error checking wie sonst machen. Apropos errors, Exceptions sollten wie der Name schon sagt nur für außergewöhnliche Fälle benutzt werden. Ansonsten kann eine Funktion auch einfach mal false zurückgeben und den Fehler loggen. Das erleichtert dann auch die Fehlersuche im Vergleich zum wortlosen abkacheln. Aber nochmal zurück zur User-Einbindung: Wenn die Benutzer schon im Voraus etwas testen können, erhöht sich die Chance, dass sie am Ende das bekommen, was sie wollen, und sie fühlen sich mit dem Produkt auch mehr verbunden, weil sie das Gefühl haben, dass sie daran beteiligt waren. Manchmal hilft es auch, sich einfach mal eine Zeit lang neben den Benutzer zu setzen, und zu gucken, wie er die Software bedient, denn hierbei erlebt man manchmal die ein oder andere Überraschung.
Zuletzt möchte ich noch gerne Donald Knuth zitieren:
Premature optimization is the root of all evil.
Also Performanceprobleme erst beheben wenn man sie mittels Profiler auch als solche identifiziert hat. Ansonsten kann man ruhig auch erstmal ein klein wenig mehr CPU-Zeit verbrauchen wenn man dafür sehr viel Entwicklungszeit einspart.
Und trotz all dieser Fähigkeiten und Hilfmittel sollte man ruhig mal out of the box denken. Manchmal ist die wirklich gute Lösung für ein vermeindliches Programmierproblem nämlich gar nicht in Software zu suchen, sondern viel eher in Hardwareänderungen oder sogar sozialen Dingen zu finden. 🙂