Diskussionen über Softwareentwicklung in der Theorie oder Methode sind oft schreckliche Schönfärbereien. Fast jeder Code, der mir in der Praxis begegnet, ist scheußlich und ich wundere mich, wie er zustande kommt. Es wäre schon interessant, diesem Widerspruch auf den Grund zu gehen. --HelmutLeitner
Optischer Ansatz: Dieser fängt schon bei den Variablennamen an. Verwendet man kurze Namen, wird der meiste Code recht kompakt. Kompakter Code enthält genug Spielraum zur ästhetischen Formatierung. Kurze Namen sind aber nur bei lokalen Hilfsvariablen sinnvoll; für die wichtigen Daten ist ein listhead->content einfach aussagekräftiger als ein l->c. Die Wahl der Namen ist eine Frage der Lesbarkeit und Wartbarkeit. Lange lesbare Namen haben aber den Nachteil, dass die Zeilen immer länger werden, vor allem bei komplexer werdenden Strukturen. Überlange oder umgebrochene Zeilen zerfleddern die visuelle Strukturierung. Eine Aufteilung von Anweisungen in mehrere Anweisungen sorgt wieder für eine Verkürzung, fügt aber ev. weitere Hilfsvariablen ein und sorgt für eine Aufblähung. In allen Fällen verliert der Code seine Kompaktheit und damit seinen ästhetischen Spielraum.
Konzeptioneller Ansatz: Der Algorithmus-Entwurf mag noch so hübsch, logisch und linear aussehen - er muss irgendwie in den von der jeweiligen Sprache zur Verfügung gestellten Strukturkonstrukten (if-else, while, for, ...) umgesetzt werden. Das geht immer nur unter Kompromissen. Sobald dann noch Effizienz in Speicherplatz oder Ausführungszeit ins Spiel kommt, hat die Struktur verloren. Der Ur-Quicksort ist auch als Programmumsetzung "hübsch" anzusehen und ästhetisch umsetzbar. Wenn die Fragen ins Spiel kommen: Geeignete Wahl des Pivot-Elements zur Vermeidung des Worst-Case; Iteration statt Rekursion; etc., dann war es das mit dem "hübsch".
Praktischer Ansatz: Solange man davon ausgeht, dass keine Fehler auftreten, ist der meiste Code ein linearer, von oben nach unten ablaufender Funktionsfluss, wie ein Buch. Sobald die Fehlerbehandlung hinzugefügt wird, wird dieser lineare Fluss zerstört. Fehler können überall auftreten, am Anfang, in der Mitte oder am Ende einer Funktion. Und jedesmal muss eine Möglichkeit geschaffen werden, den Funktionsfluss zu verlassen und den Fehler zu behandeln. Aus dem ästhetischen linearen Funktionsfluss wird ein strukturelles Desaster - if-else-Orgien, multiple returns, gotos, zusätzlicher Aufräumcode - je mehr Fehler auftreten können, desto schlimmer.
Fazit: Wenn der Code lesbar und wartbar sein soll, eine gewisse algorithmische Komplexität übersteigt, und dazu auch noch robust und fehlertolerant sein soll, kann er nur noch scheußlich aussehen - es geht gar nicht anders.
In der Praxis ist jede zweite Codezeile ein Kompromiss zwischen Funktion, Wartbarkeit und Ästhetik. Da ein Programm in der Hauptsache funktionieren soll, gewinnt meist die Funktion, wobei versucht wird, das so wartbar und ästhetisch wie möglich aussehen zu lassen.
Beim HeroProgrammer gewinnt immer die Funktion - Wartbarkeit und Ästhetik stehen nicht zur Diskussion, allein das Nachdenken darüber ist Zeitverschwendung.
Gewiß, Funktion ist nicht alles. Aber ohne Funktion ist alles nichts. [adaptiert] --hs
Man kann auch davon ausgehen, dass weniger wichtig ist, wie der Code in Funktionen realisiert wird, und den Schwerpunkt auf das Zusammenwirken von Modulen und Funktionen legen. Dann ergeben wiederum verschiedene Ansätze:
Bottom-Up Ansatz: Probleme werden dadurch gelöst, dass man sich von kleineren Teilproblemen zu den schwierigeren und größeren Aufgaben vorarbeitet. Möglicher Nachteil: Der Bottom-Up-Programmierer stürzt sich sofort auf die erkennbaren und lösbaren Probleme und produziert sehr schnell Code, die eigentlichen Probleme können lange Zeit vernachlässigt werden.
Top-Down Ansatz: Problem werden durch DivideEtImpera gelöst. Der Blick richtet auf die großen Aufgaben und Probleme, die so lange zergliedert werden, bis handliche trivial lösbare Häppchen entstanden sind. Nachteil: Wenn dabei Fehler gemacht werden, dann war der planerisch-architektonsche Vorabaufwand nur kontraproduktive Zeitverschwendung.
O-O Ansatz: Eine Variante des Bottom-Up. Als kleinste Bausteine werden Objekte verwendet. Nachteil: die entstehende Objekthierarchie wird nicht hinterfragt und kann in ihrer Struktur auch kaum mehr optimiert werden.
Linguistischer Ansatz: Eine Mischung aus Top-Down mit OO. Das Problem wird als Gesamtproblem nach DivideEtImpera behandelt, wobei die Grundelemente nicht formale Objekte, sondern Sprachobjekte (Begriffe, Konzepte) sind, deren Implementierungsform unerheblich ist.
Offene Diskussionspunkte |
...ohne Funktion ist alles nichts...
Meiner Meinung nach ist das ein Null-Argument, denn es ist ohnehin eine Minimalforderung für jede in Betracht kommende Code-Ausprägung, dass sie funktioniert. -- HelmutLeitner
Das ist ein adaptierter Sinnspruch irgendeines Schriftstellers; man darf ihn nur als Ganzes, nicht jedoch isoliert wortbezogen verstehen. Original: Gesundheit ist nicht alles, aber ohne Gesundheit ist alles nichts. --hs
Wenn der Code lesbar und wartbar sein soll und ... dann kann er nur noch scheußlich aussehen
Im Gegenteil, ich denke, diese Aussage ist ein Widerspruch in sich. Scheußlich aussehender Code ist eben nicht gut lesbar und wartbar. Man kann Prioritäten verschieden setzen. Man kann z. B. Lesbarkeit und Wartbarkeit für Performance opfern. Ich opfere lieber Performance für den Wert (die Langlebigkeit und Wiederverwendbarkeit) des Codes. -- HelmutLeitner