Ein paar Tipps zur Softwareentwicklung

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.

software_developmentDie 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.

Wizards-of-SICPAber 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.

communication-skillsOK, 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.

to-do-list-nothingFalls 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.

330px-Pair_programming_1Man 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.

Binary codeSo, 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.

homeoffice03-450x300Das 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. 😉

480px-Richard-stallmanAber 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. 🙂

ist2_5443998-hammer-and-screwPrograms 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).

orthogonalityOrthogonalitä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.

cheese460Eine 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.

Gnu_meditate_levitateFalls 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. 😉

LME_ww_031_webWenn 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. 🙂

Was machen Informatiker (bzw. Softwareentwickler im Speziellen) eigentlich so?

InformatikerBannerFalls du die Frage in der Überschrift mit sowas wie „Öh, WLANs einrichten, Viren entfernen und Office-Kram machen, glaub ich.“ beantworten würdest und dich schonmal gewundert hast, warum manch Informatiker keine Lust hat, genau diese Sachen für dich zu tun, obwohl du ihn doch mit „Das ist doch das, was du gelernt hast und dir Spaß macht.“ motivieren wolltest, ist dieser Artikel wie für dich geschrieben. 😉

Informatiker haben von Computern nur so viel Ahnung wie Astrophysiker von Teleskopen, Tischler von Stichsägen, Köche von Backöfen, Biologen von Mikroskopen oder Mathematiker von Tafeln, Zirkeln, Papier und Bleistift. Es sind jeweils nur Werkzeuge, die zwar als Mittel zum Zweck dienen, mit denen man sich aber nicht notwendigerweise darüber hinaus beschäftigt.

Ursprünglich geht es in der Informatik nämlich um die Automatisierung der Verarbeitungen von Informationen und Berechnungen, und die Grundlagen dafür wurden schon lange bevor es elektronische Computer gab entwickelt.

Informatik ist zunächst wie die Mathematik eine Strukturwissenschaft. In der Praxis angewandt hilft sie oft dabei, langweilige Arbeit anzunehmen. Im mechanischem Umherschieben und Verrechnen von Daten sind Computer extrem schnell und zuverlässig, sodass viele Dinge in der Praxis ohne sie nicht möglich wären. Die Tatsache, dass Computer immer schneller werden, ist also Voraussetzung für die Umsetzung vieler Ideen.

ComputerhistoryEin Bit ist die kleinste Informationseinheit. Es kann nur die Werte 0 und 1 annehmen. Aus 8 Bits wird ein Byte zusammengesetzt, das eine Zahl repräsentiert. Buchstaben (und somit auch Wörter, Sätze, ganze Romane) werden ebenfalls intern als Zahlen dargestellt. Jedes Byte, dass beispielsweise beim Surfen über das Internet verschickt wird, könnte auch manuell per Brieftaubeneule auf Zetteln herumgeschickt werden, und alle weiteren Vorgänge könnten ebenfalls manuell durchgeführt werden. Man kann eine Turingmaschine auf diese Art bauen, es würde aber ziemlich lange dauern bis der hauseigene Zeichner einem die Website, die man sehen will, zusammengepinselt hätte. 😉

owl_internetAußerhalb der Forschung, also in der Anwendung, ist die Informatik nicht mehr so wissenschaftlich mathematisch rein. Als Softwareentwickler baut man Dinge, die irgendeinen Zweck erfüllen sollen. Unreinheit kann dabei durch abstruse Kundenwünsche, Deadlines, der Forderung nach Effizienz (Nutzen mit wenig Aufwand (auf Seite des Entwicklers und der Hardware!)) usw. entstehen. Manchmal weiß man gewisse Dinge auch einfach nicht sicher. Bei Schnittstellen zu closed source software muss man sich darauf verlassen, dass das Spezifizierte genau erfüllt wird. Man kann nicht alles selbst nachvollziehen, und wenn etwas fremdes fehlerhaft läuft, kann man nicht einfach reingucken, woran es liegt, und den Fehler beheben.

BlackboxAber unabhängig davon, ob die Software oder die Funktion, die man implementiert, mit fremder (freier oder unfreier) oder eigenen Software-Modulen zusammenarbeitet, hat man trotzdem meistens immer verschiedene Abstraktions-ebenen. Erst das macht es möglich, sehr komplexe Vorgänge zu überblicken. Wenn man gerade in einer dieser Ebenen denkt, muss man sich nicht darum kümmern, wie die Ebenen darunter, die man benutzt, funktionieren, solange sie das tun, was sie sollen. Teilweise werden die verschiedenen Ebenen sogar in unterschiedlichen Programmiersprachen realisiert.

Computerspiel_AbstraktionsebenenZusammen mit anderen Aspekten des zu lösenden Problems ergibt sich daraus übrigens, dass es nicht „die beste Programmiersprache“ gibt, sondern die Eignung einer solchen immer davon abhängt, was man mit ihr vor hat.

Doch unabhängig von Sprache und Ebene, in der man gerade denkt, lernt man schnell, dass wenn man etwas nur irgendwie ans Laufen bekommt ohne es verstanden zu haben, es einem meistens früher oder später um die Ohren fliegt. Auch wenn man Fehler versteht und drin lässt, weil man denkt, dass die entsprechende Situation eh nicht eintreten wird; also lieber direkt elegant (d.h. simpel) zuendedenken. 😉 Manchmal war etwas auch mal ordentlich, wurde dann oft geändert und braucht nun ein Redesign, da die Chance, dass es bei weiteren Änderungen in sich zusammenfällt, immer weiter steigt. Technologische Schulden zu machen muss nicht jeden mal die falsche Entscheidung sein. Man sollte sich ihrer aber zumindest bewusst sein.

jenga_fallingKlar ist Programmierung nicht jedermanns Sache, aber manchmal versteht man etwas erst wirklich wenn man es mal selbst gemacht hat. Falls du also wissen möchtest, wie soetwas praktisch ansatzweise aussieht, ist der folgende Abschnitt hoffentlich das Richtige für dich. Wir entwickeln zusammen ein Programm, dass das klassische Kinderspiel „Fizzbuzz„, anhand dessen Kinder Division üben können/sollen, (imperativ) umsetzt.
Es soll von 1 bis 100 hochgezählt werden, wobei alle Zahlen, die durch 3 teilbar sind, durch das Wort „Fizz“, alle durch 5 teilbare Zahlen durch „Buzz“ und Zahlen, die durch 3 und 5 teilbar sind, durch „FizzBuzz“ ersetzt werden:

1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz, 16, 17, Fizz, 19, Buzz, Fizz, 22, 23, Fizz, Buzz, 26, Fizz, 28, 29, FizzBuzz, 31, 32, Fizz, 34, Buzz, Fizz, ...

Es gibt verschiedene Möglichkeiten, einen Algorithmus zu entwickeln, der solch eine Ausgabe erzeugt, einer davon sieht im Pseudo-Code wie folgt aus:

Zähler = 1
Solange der Zähler nicht größer als 100 ist, mache folgendes:
    Wenn der Zähler durch 3 und durch 5 teilbar ist:
        Schreibe "FizzBuzz".
    ansonsten:
        Wenn der Zähler durch 3 teilbar ist:
            Schreibe "Fizz".
        Wenn der Zähler durch 5 teilbar ist:
            Schreibe "Buzz".
        Wenn der Zähler weder durch 3 noch durch 5 teilbar ist:
            Schreibe den Wert des Zählers
    Schreibe ", "
    erhöhe Zähler um 1

Hier sieht man auch gut, wie wir nur auf unserer speziellen Abstraktions-Ebene bleiben.
Wie der Computer Zahlen intern repräsentiert, wie er feststellt, ob eine Zahl durch eine andere teilbar ist, und wie er Dinge auf dem Bildschirm ausgibt, interessiert uns momentan gar nicht. Wir benutzen diese Funktionen einfach.

Zur Veranschaulichung hier das ganze nochmal als Programmablaufplan (Den Zähler habe ich „Z“ genannt, der senkrechte Strich „|“ steht für „ist Teiler von“, das auf dem Kopf gelandete U „∩“ bedeutet „und“ und die rosa Rauten sind verzweigende „wenn->dann“-Abfragen.):
Fizzbuzz_ProgrammablaufplanIn einer echten Programmiersprache (hier Python) könnte das ganze dann so aussehen:

import sys
for i in range(1, 101):
    if i % 15 == 0:
        sys.stdout.write('FizzBuzz')
    elif i % 3 == 0:
        sys.stdout.write('Fizz')
    elif i % 5 == 0:
        sys.stdout.write('Buzz')
    else:
        sys.stdout.write(str(i))
    sys.stdout.write(', ')

In Echt würde man das Ganze eventuell allgemeingültiger machen (andere Teiler, andere Ersetzungswörter usw.), aber vom Grundprinzip her funktionieren auch größere Projekte ähnlich. Ein Teil der Kunst dabei ist es, komplexe Aufgaben in kleine einfachere Teilprobleme zu zerlegen. Um das gut zu können, lernt man verschiedene design patterns, Idiome usw.

Interessant an dieser Tätigkeit finde ich persönlich unter anderem, dass man trotz Wiederverwendung bereits bestehender Algorithmen doch immer wieder auf Probleme stößt, für die es so noch keine fertige Lösung gibt, und über die man erstmal wieder nachdenken muss, bis einem dann (manchmal aus heiterem Himmel, z.B. unter der Dusche) plötzlich eine Idee kommt.

Und auch wenn die Suche nach Fehlern manchmal frustrierend sein kann, kann das Gefühl, in Quellcode durch Logik eine komplexe Welt erschaffen zu haben, die sich genau so verhält, wie man sich das vorgestellt hatte, schon recht erfreulich sein. 🙂

hannibal_planZusätzlich mag ich, dass die Arbeit als Entwickler Kreativität bei der Lösungssuche erfordert, und viel Abwechslung bieten kann. Man programmiert ja nicht nur, sondern hat auch noch genug andere Dinge zu tun (siehe Softwaretechnik). Und selbst sehr gute, erfahrene und vielseitige (Software-)Entwickler können bei Weitem nicht alles schon kennen und sind in vielen Bereichen immer noch Anfänger. Außerdem besteht der Alltag in diesem Beruf aus weitaus mehr als der eigentlichen Programmierung, die ich hier hauptsächlich beschrieben habe. Ebenfalls viel Zeit verbringt man mit Planung, Analyse, Kommunikation und anderem Management-Kram.

Ebenso wie andere Wissenschaften und Ingenieursdisziplienen, durchdringt auch die Informatik sehr viele Bereiche, in denen sie nicht direkt offensichtlich ist. Du kannst ja einfach mal über den Artikel „Computer science“ aus der englischen Wikipedia drüberscrollen und nur die Bildchen angucken. Schon allein das sollte eine Vorstellung der Vielfalt vermitteln. Die einzelnen Zweige sind wechselseitig voneinander abhängig und entwickeln sich gemeinsam.

Unser Umgang mit Informationen, die Art der Fähigkeiten, die gefragt sind, und die generellen Möglichkeiten, die wir haben, haben sich unter anderem durch die Informatik in den letzten Jahrzehnten sehr stark verändert. Ich freue mich darauf, zu sehen, was in der nächsten Zeit für weitere neue Ideen entstehen, denn kaum eine Branche entwickelt sich so rasant, wie die IT. Und ich hoffe auch, dass ich weiterhin Spaß daran haben werde als Softwareentwickler meinen (wenn auch infinitesimal kleinen) Teil dazu beizutragen. 🙂

Talent oder Training, Nature or Nurture, Veranlagung oder Umwelteinflüsse?

michael_jordan_free_throw_dunkGerade wenn Leute in irgendwas besonders gut sind, sei es irgendeine spezielle Sportart, eine allgemeine athletische Fähigkeit (wie bspw. Explosivkraft), das Spielen eines Musikintruments oder einfach nur im logischen Denken, fragt man sich manchmal ganz gerne, wieviel von dieser Leistung wohl angeboren ist (Talent, Nature, Veranlagung) und wieviel erst im Laufe des Lebens (Training, Nurture, Umwelteinflüsse) dazugekommen ist. („This is ten percent luck, twenty percent skill, fifteen percent concentrated power of will…“)

Auf den ersten Blick scheint die Frage auch vernünftig zu sein, da das Ergebnis sich ja schon aus diesen zwei Komponenten zusammensetzt.

TalentTrainingAdditivBei genauerem Nachdenken, merkt man aber schnell, dass an dieser mathematischen Analogie etwas nicht stimmt, denn ohne die richtigen genetischen Voraussetzungen (Körpergröße, Hebel, Anteil an schnellzuckenden Fasern in der Skelettmuskulatur, Anzahl der Beine Oo) wird man auch mit dem besten Training kaum von der Freiwurflinie Dunken können. Wenn Michael Jordan allerdings niemals etwas mit Basketball (oder Sport allgemein) zu tun gehabt hätte, würden seine jump shots vielleicht ähnlich weit am Korb vorbeisegeln wie die deiner Oma. 😉

Es scheint also eher das Zusammenspiel (nicht die Summe) beider Faktoren zu sein, von dem das Ergebnis abhängt. Eine multiplikative Analogie beschreibt es für meinen Geschmack besser:

TalentTrainingMultiplikativEin gleichseitiges Rechteck kann noch so lang sein, die Fläche ist trotzdem Null wenn die Höhe Null ist.

Oder anders: Beim Vortrieb eines Schiffs kann man auch nicht sagen, ob die Schiffssraube oder die Stärke des angeschlossenen Motors wichtiger ist. Wenn eins kaputt ist, kann das andere noch so gut sein, es geht nix.

Falls man sich tatsächlich trauen würde, diese beiden facettenreichen Größen auf jeweils eine eindimensionale Skala, die dazu wohl noch recht willkürlich gewählt wäre, zu projizieren, könnte man beide trotzdem nicht (zumindest nicht ohne wie auch immer herbeiphantasierte Umwandlungsfunktion) miteinander vergleichen. Es wären nunmal unterschiedliche Einheiten. Zusätzlich ist es auch noch definitionsabhängig, was denn nun alles zur Veranlagung gezählt wird. Prinzipiell ist es auch veranlagt, dass man nicht unter Anenzephalie leidet und dass man keine Amöbe ist.

SchiffsschraubeBeim Hochleistungssport ist die Frage noch ziemlich harmlos und oft eher für Talentscouts interessant, wobei natürlich noch mehr an Komplexität dazukommt, da Lernkurven unterschiedlich verlaufen, und sich auch bei quasi gleichem Training verschieden überholen können. Talent ist halt doch keine eindimensionale Größe. Da viele Hochleistungssportler unter Umständen schon recht lange (incl. Frühförderung usw.) sehr optimiert trainieren, kann in solchen Fällen die Veranlagung dann aber den entscheidenen Unterschied machen. Wie sehr es sich dabei optisch Bemerkbar macht, dass man es teilweise mit ziemlich krassen Mutanten zu tun hat, hängt von der Sportart ab. 😉

Wenn es jedoch um alltägliche Dinge geht, kann es schon sein, dass auch wir wissen möchten, ob etwas eher angeboren oder eher nachträglich von Außen zugefügt (Erziehung, Lebensstil usw.) ist. Denken wir nur beispielsweise an Hyperaktivität bei Kindern, Herzinfarktrisiko, IQ, Gesundheit im Alter, Noten im Mathe-Unterricht, psychische Störungen usw. Auch bei all diesen Dingen lässt sich nicht wirklich sagen, was „mehr“ ausmacht, Veranlagung oder Umwelteinflüsse.

Klar, durch Analyse von Statistiken kann man beispielsweise herausfinden, um welchen Faktor das Risiko, bspw. an Multiple Sklerose zu erkranken, höher ist wenn ein Elternteil daran leidet, aber auch dann weiß man nichts genaues, denn Kinder teilen sich mit ihren Eltern meistens nicht nur die Gene, sondern auch die Umwelteinflüsse. Es gibt natürlich Kinder, die nicht bei ihren Eltern aufwachsen. Wenn man über genug solcher Fälle Zahlen bzgl. des zu untersuchenden Phänomens hat, kann man nur diese Auswerten, aber schon während der Zeit im Mutterleib werden sich auch Umwelteinflüsse, die sich viel später immernoch auffällig auswirken können, geteilt, weswegen auch hier eine kleine Restunsicherheit bleibt.

562px-Tubal_Pregnancy_with_embryoWenn dir demnächst also jemand erzählen will, irgendetwas sei „nur Veranlagung“ oder „nur Erziehung“ oder sonstwas, weißt du, dass die Zusammenhänge nicht so einfach sind.

Faustregel (nicht belegt, nur ein persönliches Gefühl): Wenn etwas sehr gut läuft, beispielsweise wenn Bodybuilderer/Pianisten/Physiker ziemlich krass gut sind, sagen sie über sich selbst gerne mal, dass sie gar keine „guten Gene“ hätten, sondern sich alles nur hart erarbeitet hätten. Wenn etwas schlecht läuft, beispielsweise wenn jemand Typ-2b-Diabetes hat, sagt er ganz gerne mal, dass er da nichts dafür kann, und alles angeboren sei. Beides scheint mir aber eine Form des self-serving bias zu sein. (Mehr über solche kognitiven Verzerrungen kann im Artikel „Zwei Systeme und nur ein Kopf“ nachgelesen werden.) Klar hat David Garrett auch extrem viel und gut geübt, und viele Leute, denen es gesundheitlich schlecht geht, haben auch einfach nur Pech gehabt, aber wenn man wirklich über Ursachen nachdenken will, kann es praktisch sein, solche „Schuld-Fragen“ wegzulassen.

krasser_RueckenIm Zweifelsfall kann man dem Anderen leicht vorführen, dass z.B. die Anzahl der Nasenlöcher auch durch Umwelteinflüsse verändert werden kann. Ähm, nein, lieber doch nicht. 😉

Urheberrecht, freie Software, Patente, Arbeitslosenquote und andere Utopie

Dieses mal geht es gleich um mehrere Themen, die ich dazu auch noch recht subjektiv (also ganz anders als sonst ;)) behandeln werde.
Gestern beim Training hat mein Kumpel Eugen gejammert, weil er meinen Brüllaffen-Sampler nicht bei YouTube gucken konnte. (Dafür gibt’s ihn hier zum Herunterladen. :-P) Ich hab‘ anscheinend nicht das Recht, ein Dittel eines Liedes, das mir gefällt, als Hintergrundmusik für mein nicht kommerzielles Tricking-Video auf YouTube zu benutzen. -_-

Die jetzige Form des Urheberrechts (*brech*) und die GEMA (Wem außer sich selbst nützt sie überhaupt noch?) sind ja angeblich so super wichtig, damit man als Kulturschaffender (Musiker, Autor, sonstiger Künstler) nicht seines geistigen Eigentums (Was soll das denn bitte für ein Quatsch sein?) beraubt (Mal abgesehen von der fehlenden Androhung oder Ausübung von Gewalt: Ist es danach beim „Beraubten“ nicht mehr vorhanden?) wird. (Alles, was ich hier als Blog-Autor schreibe, darfst du übrigens weitergeben, abändern oder sonstwie verwenden. Ich fänd’s nur nett, wenn du irgendwo dazu schreibst, dass du von mir inspiriert wurdest. ;-))

Wenn man irgendetwas kommerzielles, wie z.B. eine kleine Filmproduktion, machen will, scheint es ganz übel sein zu können (hab‘ ich gehört). Man muss aufpassen, dass im Hintergrund kein Radio läuft, kein Handy mit einen geschützten Klingelton runterbimmelt oder ein gecopyrightetes Bild an der Wand hängt.

Ich versteh‘ das Ganze einfach nicht wirklich. Wenn ich mir ein Lied aus dem Internet herunterlade, ist das kein Stehlen, sondern nur eine Urheberrechtsverletzung, und von diesem „Recht“ bin ich aus folgenden Gründen kein Fan:

  • In Zeiten des Internets ist es einfach anachronistisch. Informationen (Daten) können nunmal jetzt extrem leicht und schnell vervielfältigt und an andere weitergegeben werden. Man teilt gerne mit Freunden. Ich finde das schön. 🙂
  • Musiker beispielsweise konnten auch schon lange bevor es Tonträger gab, die man hätte verkaufen können, von ihrer Leidenschaft leben.

Mir würde eine andere Form von Urheberrecht, eine, die das private Kopieren entkriminalisiert, und es überflüssig macht, jemanden mit DRM auf die Neven zu fallen, besser gefallen. Vielleich ja soetwas wie eine Kulturflatrate. (Bezahlt man sowas ähnlichen nicht sowieso schon mit den ganzen Abgaben auf Festplatten, USB-Stick usw.? *g*) Es könnte eventuell sogar jeder seinen Beitrag selbst auf die von ihm bevorzugten Künstler aufteilen, so wie es der Chaos Computer Club vorschlägt.

Oder es sucht sich jeder einfach ganz aus, ob und wieviel er wem geben möchte. Überraschenderweise scheint das teilweise sogar recht gut zu funktionieren (link). 🙂

Ein anderes aber möglicherweise irgendwie verwandtes Thema sind Softwarepatente. Auch hier direkt: Die finde ich doof. 😉

John Carmack (ein bekannter Softwareentwickler) hat es mal schön formuliert:

The idea that I can be presented with a problem, set out to logically solve it with the tools at hand, and wind up with a program that could not be legally used because someone else followed the same logical steps some years ago and filed for a patent on it is horrifying.

Und das passt meiner Meinung nach wirklich ganz gut. Softwarepatente sind teilweise wirklich sehr absurd (siehe hier und hier). Als man sich dieses Verfahren vor ewigen Zeiten für mechanische Erfindungen ausgedacht hat, mag das ja irgendwie sinnvoll gewesen sein, nun kommt es mir aber eher so vor als ob Bach sich irgendeine Schlusskadenz patentieren ließ und fortan jeder, der auf die gleiche musikalische Idee kommt, gearscht ist.

Und selbst wenn man eine Idee bewusst übernimmt; Kultur basiert darauf, dass Ideen von verschiedenen Leuten weiterentwickelt werden. Alles baut aufeinander auf. Auch das größte Genie ist nur ein Zwerck auf den Schultern der Riesen.

Igor Strawinski meinte mal:

A good composer does not imitate; he steals.

Dass Software nicht nur patentfrei sondern sogar komplett frei (frei wie in Freiheit, nicht wie in Freibier) sein kann, zeigen viele erfolgreiche Projekte, die unter der GNU GPL oder einer ähnlichen Lizenz stehen. Diese Programme sind oft auch kostenlos (nun doch frei wie in Freibier) erhältlich; sie dürfen und sollen weitergegeben und verändert/verbessert werden. Der Quelltext ist frei zugänglich (open source). Das ist unter anderem toll, weil er so von vielen Leuten auf Fehler überprüft werden kann. Gerade wenn es um Sicherheit geht wirkt das auf mich wesentlich vertrauenderweckender als Sicherheit durch Unklarheit. Die beteiligten Entwickler sind teilweise oft auf freiwilliger Basis dabei. (Wikipedia basiert übrigens auf dem gleichen Prinzip.) Dieses Modell funktioniert überraschend gut; die resultierende Qualität der Software ist meist sehr hoch. Vielleicht liest du meinen Blog (benutzt WordPress, GPL) ja gerade sogar in einem freien Browser wie Firefox (MPL/GPL/LGPL) oder Chrome (BSD-Lizenz). Der hostende Server benutzt vermutlich Apache (Apache License) unter Linux (GPL) oder Unix (CCDL). All das ist frei. =) Ein weiterer Vorteil von freier gegenüber proprietärer Software ist der, dass man sich nicht von einem Hersteller abhängig macht. Closed source software benutzt gerne Datenformate ohne offene Spezifikation. Aber nicht nur das. Wenn der Hersteller einer solchen Software pleite geht (oder einfach mehr keine Lust auf das Produkt hat), ist es aus mit Support. Eventuell hat man seine IT-Infrastruktur aber schon davon abhängig gemacht. Nun wird es teuer (nicht nur in Sachen Geld, sondern auch bezüglich des Arbeitsaufwands). Man muss halt irgendwie aus dem untergehenden proprieätren Käfig herauskommen. Freie Software könnte man immer selbst an seine neuen Bedürfnisse anpassen bzw. von einem Entwickler anpassen lassen. Aus all diesen Gründen bin ich dafür, dass in öffentlichen Einrichtungen wenn möglich freie Software eingesetzt wird.

Der gute alte Linus hat mal gesagt:

Software is like sex; it’s better when it’s free.

So, als Überleitung zum nächsten Teil muss ich gerade nochmal zurück zum Thema Musikkopieren und co.

Dieser mythische Jesus, der wohl die Ausgeburt des Guten sein sollte, hat der Legende nach 5000 Leute mit nur einem Brot satt gemacht. Dieser fiese Brotkopierer! Wenn man das ständig so machen würde, würden doch fast alle Bäcker (in der Analogie: Angestellte der Musikindustrie) arbeitslos werden!

Tjoa, so ist das nunmal mit fortschreitender Technik. Ganz früher war eigentlich jeder damit beschäftigt, durch Jagen und später durch manuellen Ackerbau dafür, dass er genug zu Essen hatte, zu sorgen. Als man dann auf die Idee kam, Ochsen vor den Pflug zu spannen, konnte man mit weniger menschlicher Arbeitskraft mehr Nahrung produzieren. Mit moderner Agrartechnik geht das noch viel effizienter. Eigentlich ist es doch schön wenn weniger Leute dafür, dass für alle genug Güter produziert werden, ackern (höhö) müssen. So gesehen stellt dich die Frage, ob es vielleicht nicht sogar ein positives Zeichen ist, wenn nicht mehr so viele Menschen arbeiten gehen müssen. Vielleicht hören wir ja irgendwann auf, Bullshit-Jobs zu produzieren, und es wird dann so sein, dass Leute nur noch das tun, was ihnen Spaß macht. Musiker, Dichter, Frisöre (und was man sonst alles auch nicht von Maschinen/Robotern/Computern machen lassen kann oder will) wären dann bestimmt immernoch ein paar dabei. Ich würde vermutlich auch noch weiterhin programmieren wollen. 🙂

Realismus und evolutionäre Stabilität hin oder her – man darf ja mal Träumen. Gerade scheint mir die Abendsonne beim Schreiben nämlich so schön auf den Bauch. ^_^

PS: Ich werde mich bemühen, demnächst nochmal etwas tiefsinniger und objektiver zu schreiben. 😉

Mathematik: Entdeckung oder Erfindung?

Mathematik ist zwar unter anderem eine wichtige Sprache für Formulierungen innerhalb der (Natur-)Wissenschaften, als solche selbst jedoch eine Strukturwissenschaft. Es werden also scheinbar keine Theorien mit konkreten Vorhersagen über die Wirklichkeit aufgestellt, die man dann versucht experimentell zu widerlegen und als wahrscheinlich richtig ansieht wenn die Widerlegung immer scheitert (die Vorhersagen also stimmen), stattdessen werden aus wenigen grundlegenden Axiomen logische Schlüsse gezogen, die sich innerhalb dieses Sytems tatsächlich beweisen (nicht nur nicht widerlegen) lassen und damit dort dann wahr sind.

Somit drängt sich die Frage (die ich schon hier gestellt habe) auf, ob die Mathematik eine Erfindung von uns Menschen oder eine dem Universum inhärente Wahrheit ist, die wir (und zumindest implizit auch andere Lebewesen) entdecken.

Im Grunde geht es bei dieser Frage um die Axiome, aus denen der Rest hergeleitet wird, wie z.B. „Jede natürliche Zahl n hat genau einen Nachfolger n‘.“ aus der Peano-Arithmetik. Wenn man solche Dinge aus in uns intuitiv vorhandenen Regeln der Mengenlehre extrahiert, reduziert sich das Problem darauf, wo diese Intuition herkommt. Aber zunächst einmal: Wie sieht sie aus? Unser physikalisches Universum scheint (zumindest auf makroskopischer Ebene) die Eigenschaft zu haben, diskrete Objekte beinhalten zu können. Wenn alles einfach nur Suppe wäre, würden wir vermutlich (zumindest wenn wir als Grundannahme setzen, dass wir tatsächlich existieren und unsere Sinne zumindest manchmal sinnvolle Daten liefern, ansonsten sind wir eh einfach nur raus) nicht die Vorstellung von einzelnen (zusammenzählbaren usw.) Objekten entwickeln.

Aus diesen Mengen ergibt sich dann, was wir mit ihnen tun können:

usw. mit den anderen Operationen, die auch andere Sachen machen, als mit der Mächtigkeit von Listen zu operieren. (Mehr dazu hier: http://www.youtube.com/watch?v=14JavH4Rk7k#t=8m20s) Der schlaue David sagt übrigens, dass sich aus der rekursiven Definition der Addition (a+0 = a, a + b‘ = (a+b)‘), ergibt, dass das n‘ von oben (also der Nachfolger von n) dann n+1 ist. 😉

Wenn wir mathematisch rumhantieren, vergessen wir nur gerne mal, dass all diese Grundvorstellungen in den verschiedendsten Kulturen von Generation zu Generation gleichermaßen entstehen (es wäre mal witzig, zu erfahren, ob Außerirdische auf die gleichen Dinge kämen), weil sie einfach jeder persönlich täglich empirisch implizit anwendet und somit quasi ständig überprüft. Wenn zwei Äpfel und drei Bananen nicht immer sondern nur manchmal fünf Öbste ergeben würden, sollte das doch irgendwann mal auffallen, oder? 😉 Im Prinzip ist Addition also eine Theorie über das Verhalten der Natur.

Logik, die wir benutzen, um aus solchen Grundlagen komplexere mathematische Sätze herzuleiten, ist ebenfalls kein rein theoretisches Konstrukt sondern aus ganz praktischer physikalischer Erfahrung gewachsen.

„Wenn ich in den Pool springe (A), werde ich nass (B).“ ist eine logische Implikation. (A -> B, Dass ich in den Pool springe, ist also eine hinreichende (aber nicht notwendige) Bedingung dafür, dass ich nass werde.) Mit anderen Verknüpfungen der Aussagenlogik verhält es sich ähnlich. Sie sind Abstraktionen alltäglich erlebbarer physischer Phänomene.

Somit sind die Grundlagen wie auch das Werkzeug, mit dem man aus ihnen komplexere Sachen herleitet, empirisch begründete Vorstellungen davon, wie unser Universum so zu funktionieren scheint. Die daraus ziehbaren mathematischen Schlüsse funktionieren ebenfalls prima, um überprüfbare Naturgesetze zu formulieren. Wenn das nicht klappen würde, könnte ich das hier in dieser Form nicht schreiben, weil es gar nicht möglich wäre, Computer zu konstruieren. Alles, was du gerade um dich herum siehst, funktioniert übrigens ziemlicher sicher nur, weil die Naturgesetze immer und überall zuverlässig greifen, und der ganze Technik-Schnickschnack nur, weil irgendwer sie herausgefunden/verstanden hatte, und mit diesem Wissen den Ingenieuren erst die Möglichkeit gab, sinnvolle Sachen zu bauen. 🙂

Momentan denke ich also, dass wir es bei Mathematik und Logik in dem Maße mit Entdeckungen zu tun haben, wie das bei den Naturgesetzen auch der Fall ist. (Klar, man kann sagen, dass die Modellvorstellungen/Theorien, die man sich von irgendwelchen Phänomenen macht, erfunden sind, um diese zu erklären, aber du weißt vermutlich hoffentlich, was ich meine. ;)). Die tatsächlich bewiesene Richtigkeit eines Satzes innerhalb eines strukturwissenschaftlichen Systems ist unabhängig von dessen Ursprüngen trotzdem absolut wahr (und nicht nur wahrscheinlich nicht falsch), weil es dabei dann nur noch um die Konsistenz innerhalb dieses Systems geht.

Warum unser Universum allerdings so mathematisch drauf ist, ist wieder eine andere Frage. Wenn es launischer wäre könnten wir jedoch vermutlich auch kaum solche komischen Fragen stellen. Oh, ist das Universum eigentlich ein INTJ? Informationen über sein inneres muss man ihm aufwendig aus der Nase ziehen (Introvertiert), es basiert auf wenigen abstrakten Prinzipien (iNtuitiv), es ist logisch (Thinking), und funktioniert zuverlässig (Judging). 😉

Natürlich beißt sich die Katze irgendwo selbst in den Schwanz wenn man Logik benutzt, um über die Wahrheit der Logik nachzudenken, allerdings funktioniert sie ja bekanntlich recht gut, was wir ja wissen, weil wir es empirisch (und damit logisch) überprüft haben. Oh, verdammt! 😀

Für mich fühlt sich dieser ganze Rekonstruktions-Kram nach der Postmodernen, irgendwie so an wie nach ’nem Sturm, der alles weggefegt hat, aus seinem Loch zu kommen und zu gucken, was übrig gelassen wurde und ob man mit dem, was man von früher kennt, irgendwas neues schönes bauen könnte. 😉

Emergenz und das Spiel des Lebens bzw. die Hochzeit von Reduktionismus und Holismus

Mit dem Spiel des Lebens meine ich Conway’s Game of Life (GoL), bei dem es sich um einen zweidimensionalen zellulären Automaten handelt. Stell dir einfach ein Blatt kariertes Papier vor, auf dem manche Zellen dunkel markiert (lebendig) und andere leer (tot) sind.

Bewegung kommt generationsweise ins Spiel. Die Regeln für die Berechnung des Spielfeldes in der nächsten Generation sehen wie folgt aus:
1) Wenn eine leere Zelle genau drei volle Nachbarn hat, wird sie in der Folgegeneration voll.
2) Volle Zellen mit weniger als zwei oder mehr als drei vollen Nachbarn sind in der Folgegeneration leer.
3) Alle Zellen, auf die keine der beiden Regeln zutrifft, bleiben unverändert.
Dadurch sind verschiedene statische

und auch oszillierende Objekte möglich.

Wenn man das Ganze auf einem genügend großen Spielfeld durchzieht (da es ziemlich viel Arbeit wäre, das selbst zu machen, lässt man das am Besten einen Computer für sich erledigen), kommen dabei interessante Sachen heraus. Beispielsweise gibt es Glider, die langsam über das Feld wandern.

Sowas hier (Gun)

ist auch super, weil es zeitlich animiert Glider abfeuert:

Spätestens bei solchen komplexen Gebilden wie dem Breeder
ist man an einem Punkt angelangt, den niemand von Anfang an direkt aus den Regeln hätte vorhersagen können ohne sie tatsächlich auszuprobieren/anzuwenden.
Der Breeder ist somit ein sehr gutes Beispiel für Emergenz. Seine Eigenschaften (Fortbewegung, Produktion von Guns, quadratisches Wachstum) ergeben sich zwar zwangsläufig aus den einfachen Grundregeln des Spielsystems (Wir machen ja die ganze Zeit nichts anderes als diese simplen Regeln anzuwenden.), sind aber trotzdem auf einer anderen Emergenzebene angesiedelt.

Andere Beispiele für Emergenz gibt es viele. Die Beschaffenheit und das Verhalten eines Ameisenhaufens (Schwarmintelligenz) gegenüber der Beschaffenheit und dem Verhalten einer einzelnen Ameise, Aktivitätsmuster (incl. Wille, Bewusstsein und Ego, dazu aber vielleicht ein anderes Mal mehr ^^) im Gehirn gegenüber der Anatomie einzelner Neuronen, das Verhalten von Gemeinschaften (Börse, Markt, Freundeskreis) gegenüber den Eingenschaften eines einzelnen Menschens etc.
Die Zusammensetzung von Aminosäuren (den Grundbausteinen des Lebens) aus einfachen Molekülen emergiert durch simple chemische Regeln von Abstoßung und Anziehung, ebenso die Struktur von Schneeflocken. Letztendlich ist auch die Struktur des Universums (Filamente, Voids, Galaxienhaufen usw.) aus den Regeln der Gravitation (und natürlich der Quantenmachnik, wir wollen ja nicht vergessen, dass das, was wir nächtlich am Himmel sehen vermutlich die Auswirkungen von minimalen Dichteschwankungen im ganz jungen Universum sind) emergiert. Oh, Wikipedia auch. Wenn man will kann man das Bild hier ab der Physik von rechts nach links lesen und hat aufeinander aufbauende Emergenz-Ebenen. So, nun ist es aber genug. ^_-

Aus einfachen Grundregeln einzelner Elemente können also sehr komplexe (auch selbstorganisierende) Systeme entstehen. Wenn man ein solches emergentes Verhalten beobachtet, meint man zunächst meist nicht, dass die einzelnen Komponenten und Regeln, aus denen sich alles automatisch (ganz ohne großen Bauplan) ergibt, so simpel sind, wie sie es aber nunmal manchmal sind. Bei Emergenz geht es also darum, dass das Ganze nicht nur die Summe seiner Teile ist, sondern zusätzlich aus den Beziehungen der Teile untereinander besteht, wodurch sich Phänomene zeigen, die man den einzelnen Elementen nicht zugetraut hätte.

Wer das ganze (GoL) mal selbst ausprobieren will, dem empfehle ich die Software Golly, der selbst schon viele einfache bis sehr komplexe Beispiele beiliegen. Wenn man sich mit dem Verständnis, wie das ganze funktioniert, einige Strukturen, die im GoL möglich sind, anschaut, kann die Schönheit dieser einen echt begeistern. <3

Das Titelbild habe ich erzeugt, indem ich das Bild meiner Webcam binarisiert habe, und den Algorithmus darauf angewendet habe. Mein Programm in Python 2 mit OpenCV dazu gibts hier: http://daiw.de/DemDobiSeinBlogFiles/game_of_life.py
Umgesetzt sind die Regeln in dieser Version mittels einer Faltungsoperation, wie man sie auch sonst in der Bildverarbeitung benutzt.

Das GoL ist übrigens genau wie das Lorenzsche Wasserrad (siehe von Wasserrädern, Kochtöpfen und Wettervorhersagen) ein nicht-lineares System, bei dem kleine Änderungen (Man invertiert z.B. nur eine Zelle beim Breeder.) das ganze Verhalten im Großen (Z.B. der Breeder breedet nicht mehr. ;)) bewirken können.

von Wasserrädern, Kochtöpfen und Wettervorhersagen

Stellt dir (als Gedankenexperiment) ein Rad mit Eimern dran (links oben auf dem Whiteboard) vor. Oben rauscht fließendes Wasser runter und füllt einen Eimer, der gerade oben ist auf. In den Eimern sind Löcher, sodass sie ihr Wasser wieder langsam verlieren. Wenn die Wasserzufuhr gering ist, dreht sich das Rad kontinuierlich und periodisch. Man kann genau berechnen, in welcher Position es in 42 Jahren, 127 Tagen, 8 Stunden, 3 Minuten und 23.123 Sekunden sein wird. Die Phasenraumtrajektorie (Diagram mit Rotationswinkel auf der X-Achse und Geschwindigkeit auf der Y-Achse) sieht dann ähnlich langweilig aus wie das rechts unten auf dem Board.

Erhöht man die Wasserzufuhr jedoch genug, ergibt sich irgendwann total chaotisches Verhalten. Das Rad pendelt dreht manchmal weiter, manchmal pendelt es zurück. Das ganze ist zwar immernoch deterministisch, aber nicht mehr periodisch. Eine analytische Lösung der Differentialgleichungen kann man sich abschminken. Wenn man wissen will, in welchem Zustand das Rad an irgendeinem Zeitpunkt in der Zukunft ist, muss man Schritt für Schritt rechnen (und auch dann je nach Verfahren mehr oder weniger ungenau), was es tut.

Dazu habe ich eine kleine Simulation in Python 3 programmiert: http://daiw.de/DemDobiSeinBlogFiles/lorenz_waterwheel.py
Die graphische Ausgabe der Phasenraumtrajektorie sieht dann beispielsweise so aus:
oder so:

Minimale Unterschiede in den Anfangsbedingungen können entscheiden, ob das Rad in einer späteren Situation den Umlauf schafft oder zurückpendelt. In der Chaosforschung sind solche Phänomene als Schmetterlingseffekt bekannt.

Beispielsweise habe ich bei diesen Simulationsdurchlauf die Anfangsfüllhöhe der Eimer nur um ein Zehntausendstel das Wasserzuflusses pro Zeiteinheit

gegenüber diesem Durchlauf
geändert. (Dieses mal ist der Rotationswinkel des Rads gegen die Zeit aufgetragen.)

Wenn man beide Diagramme übereinander legt sieht man sehr gut, dass erst ab ca. der 14. Schwingung ein sichtbarer Unterschied auftritt, auf den dann auch schnell die Bifurkation folgt. Hier liegt in dem Fall also der tipping point.
Gemeinsam mit einem Kochtopf hat dieses System, dass es an einer Stelle (hier oben, beim Topf unten) Energie (hier potentielle Energie vom Wasser, beim Topf Wärme) aufnimmt, sich dadurch bewegt (beim Topf Konvektionsbewegungen) und diese verteilt wieder abgibt. Der Weg eines Wassermoleküls im Topf beim Kochen ist auch chaotisch.

Das Wetter benimmt sich da nicht besser. Die Sonne erhitzt gewisse Teile der Atmosphäre und es entstehen Konvektionsbewegungen (und noch vieles mehr). Auch beim Wetter können minimale Änderungen später große Auswirkungen haben. Selbst wenn der Planet mit Messstationen zugekleistert wäre, und man ein perfekt funktionierendes mathematisches Modell zur Vorhersageberechnung hätte, würden die mikroskopischsten Ungewissheiten über die Zustände, die zwischen den Stationen herrschen, mittelfristig beliebige makroskopische Auswirkungen haben können, weshalb sich einigermaßen zuverlässige Prognosen auch nur für wenige Tage im Voraus machen lassen.

Wenn sich das Wetter langfristig also nicht präzise vorhersagen lässt, dann ist das, was man da sieht, kein Mess-/Rechenfehler oder gar die Unfähigkeit der Meteorologen sondern das diesem nichtlinearen System selbst inhärente chaotische Verhalten. 🙂

Unser eigenes Leben ist trotz eventueller Planung auch nicht unbedingt wesentlich vorhersehbarer, denn aus der Chaosforschung ist nicht nur bekannt, dass ein System instabiler wird, je mehr Energie man zuführt (wie beim Wasserrad und dem Kochtopf), sondern auch je mehr Abhängigkeiten/Verknüpfungen zwischen den Elementen bestehen, und davon haben wir ja nun wirklich viele. Man könnte sich vorstellen, dass man gar nicht mit Tricking angefangen hätte wenn man vor Jahren nicht aus Langeweile einen Link zu einem Sampler in einem Kraftsportforum angeklickt hätte, oder sogar dass man mit seiner jetzigen Frau vielleicht gar nicht zusammen wäre wenn vor vielen Jahren ein Mitspieler aus der eigenen Basketballmannschaft in der Aufstiegsrunde den entscheidenden Dreier nicht versenkt hätte, und somit ihr Bruder nicht in die eigene Mannschaft gewechselt hätte, und man sie deshalb nicht kennengelernt hätte usw. 😉

(Um hier nicht der trügerischen Illusion, es gäbe soetwas wie Schicksal, das solche Dinge bestimmt, zu unterliegen, muss man nur genügend Phantasie für alternative Verläufe mitbringen. :))

Chaos Theory by Conspiracy

Immernoch meine liebste 64k intro*.


Download: http://www.pouet.net/prod.php?which=25774
Video: http://www.youtube.com/watch?v=MAnhcUNHRW0

*Bei 64k intros der demoscene (mehr solches Zeug gibt’s übrigens zum Beispiel hier.) geht es darum, ein Stück Software zu entwickeln, dessen Größe im kompilierten Zustand insgesamt unterhalb der im Namen genannten Grenze bleibt. (64k sind ungefähr soviel wie 4 Sekunden einer MP3.) Das Programm soll in Echtzeit eine hübsche Animation mit Musik berechnen und anzeigen. Chaos Theory ist in diesem Sinne ein mich doll beeindruckendes Kunstwerk.