Die brand eins titelt gerade mit “Das Erotische setzt das Geheimnis voraus. Wo es ganz verschwindet, beginnt die Pornografie.” (Byung-Chul Han, Ausgabe 7/2011)
Das bezieht sich im Heft auf das gesellschaftliche Top-Thema Transparenz. Aber mich hat der Ausspruch zum Nachdenken über Softwareentwicklung angeregt. Die kommt mir in der Praxis vieler Projekte nämlich wie die Kunst der Verhüllung vor: wie Erotik.
Zwei aktuelle Beispiele ganz unterschiedlicher Art: Zuerst ein Codeausschnitt aus der dotnetpro 7/2011:1
Ein, wie ich finde, sehr erotisches Stück Code. Der Autor verhüllt mit Geschick die Funktionsweise. Was tut der Code? Wie tut der Code das? Sprachkonstrukte, Whitespace und Namensgebung kommen kunstvoll zum Einsatz zur Komposition eines geheimnisvollen Ganzen.2
Ganz anders und doch ebenfalls hocherotisch dieser Code aus einem Blog:3
Hier ist die Intention zwar viel deutlicher – doch das kompensiert der Autor mit technologischer Rafinesse. Ein Meister des lambda-Schleiertanzes legt er alles in wenigen Zeilen offen – und verwehrt dem Leser doch einen schnellen Durchblick. Das Verständnis der Lösung, warum sie tatsächlich tut, was sie verspricht, will erarbeitet sein. Eleganz als höhere Form der Erotik.
Doch während Erotik in der Kunst einen hohen Stellenwert hat und von Geschmack zeugt, da ziehe ich für den Broterwerb durch Softwareentwicklung weniger davon vor.
“Auf der Arbeit” brauche ich kein Geheimnis. Geheimnis – gewollt oder ungewollt – ist kontraproduktiv. Geheimnisse machen Mühe, wie jeder weiß, der Krimis liest. Es dauert, bis man sie entschlüsselt hat. Und am Ende ist man womöglich gar nicht sicher, ob man das vollständig geschafft hat.
Wenn Erotik für Geheimnis steht und Porno für Geheimnislosigkeit, Unverhülltheit, Klarheit, Direktheit, dann bin ich für mehr Porno in der Softwareentwicklung. Gerne Erotik, wenn ich Zeit dafür habe. Gerne auch “höhere Erotik”: Eleganz. Im Zweifelsfall jedoch bitte krasse Nackheit.
Ich will mit Code umgehen, der sich nicht verhüllt. Enthüllen ist etwas für Journalisten. Auspacken ist etwas für Weihnachten. Geheimnisse lüften überlasse ich gern den Drei Fragezeichen.
Code hingegen soll alles zeigen. Da will ich schnellstmöglich zur Sache kommen. Programmiervorspiel, nein danke!
Ich mag pornografischen Code. Er soll zum Beispiel “intention revealing” sein:
A design in which the names of classes, methods, and other elements convey both the original developer's purpose in creating them and their value to a client developer.
Und Code soll sich mir attraktiv aus unterschiedlichen Entfernungen darstellen. Aus der Ferne soll er eine wohlgestalte Erscheinung abgeben. Bin ich näher an ihm dran, zeigt er mir mehr Details, die mir Spaß machen. Bis ich zum Schluss ganz nah in der IDE handgreiflich werde, um seine Strukturen leicht an neue Anforderungen anzupassen.
In der Erotik zählt Geschwindigkeit nicht. Da steht die Kunst im Vordergrund.
In der täglichen Arbeit jedoch, halte ich es mit der Königin in Hamlet (2. Akt, 2. Szene):
POLONIUS
So wäre dies Geschäft nun wohl vollbracht.
Mein Fürst und gnädge Frau, hier zu erörtern,
Was Majestät ist, was Ergebenheit,
Warum Tag Tag; Nacht Nacht; die Zeit die Zeit:
Das hieße, Nacht und Tag und Zeit verschwenden.
Weil Kürze denn des Witzes Seele ist,
Weitschweifigkeit der Leib und äußre Zierat:
Faß ich mich kurz. Eur edler Sohn ist toll,
Toll nenn ichs: denn worin besteht die Tollheit,
Als daß man gar nichts anders ist als toll?
Doch das mag sein.KÖNIGIN
Mehr Inhalt, weniger Kunst!
Ich wünsche mir mehr Inhalt, Inhalt in Form klarer Funktionsweise, klarer Struktur.
Denn solange nicht nackte Klarheit unser Hauptziel ist bei der Codierung, haben wir ein Verständnisproblem. Kompaktheit oder Eleganz sind zweitrangig. Was zählt, sind Effizienz und Effektivität bei der Lektüre von Code.
Also: Mehr Porno, weniger Erotik in der Programmierung.
Fußnoten
1 Wenn Sie den Code auch in der Vergrößerung nicht entziffern können, macht das nichts. Er würde auch in Originalgröße sein Geheimnis nicht leicht preisgeben. Ich habe deshalb eine bidlich längere Darstellung einer besser lesbaren vorgezogen.
2 Tut mir leid, Andreas, ich kann mir die Ironie angesichts deines Codes nicht verkneifen. Bitte nimm es nicht persönlich. Ich spendiere ein Bier, wenn wir uns mal wieder sehen.
3 Sergej, auch für dich ein Bier bei der nächsten Begegnung.
25 Kommentare:
Den Calculator Code finde ich alles andere als verschleiernd. Er ist kurz und knackig. Tolle Arbeit
@Christoph: Zeig den Code 10 Entwicklern "auf der Straße" - 9 werden ihn nicht innerhalb von 5 Minuten verstehen. Und mit "Verstehen" meine ich, ihn reproduzieren können.
Kürze oder gar Eleganz sind nicht zwangsläufig dasselbe wie Verständlichkeit.
Nun magst du sagen, "Dann sind die 9 Entwickler eben schön doof. Sie begreifen einfach nicht, was higher order functions sind. Besser sie setzen sich auf den Hosenboden und lernen das. Dann verstehen sie solch eleganten Code."
Da ist auf der einen Seite etwas dran - aber es hilft halt nichts. Bis die 9 Entwickler die Zeit gefunden haben, das zu lernen, ist der Code immer noch geheimnisvoll.
Die Frage ist also, wie wir hier und heute Code schreiben, der für die meisten Entwickler verständlich ist. Brauchen wir dafür neue Mittel? F#, Clojure, Monaden, bessere Typtheorien...? Das bezweifle ich.
Wir müssen nicht komplizierter werden, sondern einfacher.
"Brauchen wir dafür neue Mittel? F#, Clojure, Monaden, bessere Typtheorien...? Das bezweifle ich.
Wir müssen nicht komplizierter werden, sondern einfacher."
Das halte ich für eine durchaus gefährliche Ansicht.
Solche Technologien existieren, um uns als Programmieren das Leben zu erleichtern, um mehr Funktionalität schöner und kürzer ausdrücken zu können. Ich denke doch, man sollte die einem gebotenen Möglichkeiten (z. b. Extension Methods in C#/.net) auch nutzen, um sein Ziel mit der größtmöglichen Eleganz zu erreichen. Oder sollen wir jetzt alle ANSI-C99 schreiben, nur weil es noch ein paar Programmierer gibt, die möglicherweise noch nie etwas von Objektorientierten Sprachen gehört haben?
Es gehört doch zu unserem Beruf, jeden Tag etwas neues dazuzulernen, und wenn ich z. B. mit dem Calculator-Code konfrontiert werde, dann muss ich mich doch vielleicht mal eine Stunde hinsetzen und das verstehen, doch dabei lerne ich etwas dazu, und das hilft mir bei meinen zukünftigen Tasks nur weiter, bei denen ich dann wieder Zeit durch die neu erlernten Fähigkeiten einsparen kann...
Der Code ist geheimnisvoll für die Leute, die mit den Grundkonzepten des Paradigma nicht vertraut sind - natürlich. Aber für die Leute, die mit FP vertraut sind, ist er dafür viel klarer als hätte man ein "primitiveres" Konstrukt gewählt.
Du bist vielleicht schon einmal über den Kochbuchvergleich gestolpert. Ich finde den eigentlich ganz treffend:
http://eloquentjavascript.net/chapter6.html
Zunächst einmal musst du wissen, was Blanchieren, Dünsten, Grillen etc. ist. Bist du mit diesen Dingen nicht vertraut wird sich jedes Kochbuch geheimnisvoll lesen. Sobald du sie aber kennst, sind die Bücher nicht mehr so mystisch und du wirst in der Lage sein kurze, knackige Rezeptangaben zu verstehen und umzusetzen.
Ich denke nicht, dass wir in der Software Entwicklung eine Alternative zu dem stetigen Lernen neuer Paradigma, Sprachen und Konstrukte haben.
@Anonym: Puh, eine "gefährliche" Ansicht habe ich geäußert... Da möcht ich antworten: Definiere "gefährlich".
Hast du Angst, dass Entwickler stehenbleiben? Gefährlich ist, dass sie nicht mehr dazulernen?
Dann sag ich mal, was wir 1980 gesagt haben: "Don´t wait for 1984. You can panic now!" :-)
Dieser gefährliche Zustand ist schon erreicht.
@Anoynm, @Christoph: Lernen ist immer nötig. Keine Frage. Und wer mich kennt, der weiß, dass ich da immer eher mehr von Entwicklern fordere, als weniger.
Natürlich soll die Entwicklung auch weitergehen. Ist nicht nur Last, sondern auch Lust, neue Spielzeuge zu bekommen.
Nur sind wir eben keine Kinder. Wenn man uns einen Stift in die Hand gibt, ist nicht jedes Bild mit "Toll hast du das gemacht!" zu kommentieren. Wir müssen mit unseren Stiften zügig Wert für Geldgeber herstellen und (!) darüber hinaus sicherstellen, dass unsere Produkte lesbar und evolvierbar sind; sonst können wir morgen nicht weiteren Wert hinzufügen.
Also: Vorsicht mit die Stifte ;-)
Weiter im Teil 2 des Kommentars...
Teil 2:
Komischerweise hat das erste Beispiel keine Kritik von Kommentatoren angezogen, warum?
Beim zweiten jedoch fühlt ihr euch bemüßigt zu mahnen. Warum?
Weil es hier ans Heiligste geht der Programmierung: an die Technik, ans Geheimnis. Wir kontrollieren, beherrschen etwas, das andere nicht können.
Und innerhalb unserer Zunft gibt es dann noch Leute, die beherrschen auch etwas, das andere nicht können.
Beherrschung adelt. Wer möchte aber nicht geadelt sein?
Mit OO adelt sich heute niemand mehr. Mit FP hingegen... Und so entwickelt sich die Kunst fort. Klar.
Mir geht es um etwas Vorsicht dabei. Die Grenze zwischen verständlicher Eleganz und schwer/unverständlicher ist dünn.
Natürlich hängt die mit dem Kenntnisstand der Leser zusammen. Wer keine lamdas kann, der versteht es eh nicht. Wer nicht blanchieren kann, der versteht das Rezept nicht. Also, Leute, lernt die Basics. Know your tools.
Stimmt auch. Bin dafür.
Dennoch ist nicht jedes Tool, das es gibt, und jede Anwendung eines Tools auch verständlich.
Ein triviales Beispiele: Was ist "auf einen Blick" einfacher zu verstehen. Dies
z = f(g(h(x)));
oder jenes:
a = h(x);
b = g(a);
z = f(b);
Natürlich ist jenes leichter zu verstehen. Denn jenes kann ich einfach von oben nach unten lesen. "Aha, erst tut h() etwas, dann g() und schließlich f()."
Der geübte Programmierer versteht natürlich auch das erste Beispiel. Klar. Aber mir geht es um den Unterschied. Hier ist es nur ein Hauch, woanders sind es 2, 3, 4, 10, 20 Minuten Unterschied.
Schachtelung ist einfach schwerer zu verstehen als Sequenz. Ansonsten würde eine Metrik wie die Zyklomatische Komplexität keinen Sinn ergeben.
Schachtelung ist nun ein Konstrukt, das jeder Entwickler versteht. Sollte man deshalb aber schachteln? Soll man etwas tun, was man kann, weil man es kann?
Nein. Können ist kein Wert. Verständlichkeit und Evolvierbarkeit jedoch, das sind Werte.
Deshalb bleibe ich dabei: Der lambda-Jongleur muss sich sehr bewusst sein, warum er soviele Bälle in die Luft wirft. Weil er es kann? Oder weil das echt einen Verständnisvorteil bringt?
Das vorgestellte Beispiel aus dem Blog ist da für mich mindestens grenzwertig. Sergej hat gezeigt, was er kann. Toll! Aber aus meiner Sicht Erotik fürs stille Kämmerlein.
Hier zwei Gründe, um das zu substanzieren:
1. Die Lösung verbirgt strukturell, dass die Operatoren in einer hierarchischen Beziehung zueinander stehen. Operatorpräzedenzen werden hier nicht deutlich. (Klar, am Ende stecken die in der Reihenfolge; doch "auf der Hand liegen" ist etwas anderes.)
2. Die Lösung gut erweiterbar, wenn einfach weitere binäre Operatoren mit unterschiedlicher Präzedenz dazukommen, z.B. "^" für die Potenz. Unäre Operatoren oder Klammern jedoch... die passen da nicht so einfach hinein. Die grundsätzliche Evolvierbarkeit ist also begrenzt.
Bottom line: Lernen, ja klar. Immer. Dennoch Vorsicht bei der Anwendung des Gelernten: "Mehr Inhalt, weniger Kunst!"
Mal provokant gesagt: Dann nehme ich auch ein ellenlanges if-else-if-else-if-else-if-else an Stelle des Strategy-Patterns, das ist nämlich auch für 9 von 10 Leuten "auf der Straße" leichter zu verstehen.
IMHO einer der größten Fehler ist, das englische "simple" immer mit "einfach" zu übersetzen. Das klingt nämlich nach "trivial", meint aber "simpel" im Sinne von "einfach, aber genial" ...
Zu sagen, weil die Mehrheit es nicht versteht, wäre es zu kompliziert, damit macht man es sich sehr leicht - und damit leistet man auch der Faulheit Vorschub. Denn wozu was neues lernen?
Im Zweifelsfall liegt der Fehler, wenn ich etwas nicht verstehe, ja nicht bei mir, sondern bei dem, der die vermeintlich zu komplizierte Lösung entwickelt hat.
Wenn man das mal auf Kindererziehung übertragen würde ... puuuuuuh :-/
Das Problem mit dem Wissen... welches Grundwissen darf ich denn voraussetzen. Als Befürworter des Clean Codes kann ich sagen, Verständlichkeit siegt.
Die sieht bei FP anders aus als bei OOP. Da könnten wir hier wieder ne Grundsatzdiskussion anfangen.
Die Frage ist: Wann fängt explizit and und wo hört implizit auf? Abstraktion soll uns auf ein höheres Niveau heben ohne dabei Details wegzulassen.
Aber wo und wie ziehen wir diese Grenzen? Wer mit FP nicht vertraut ist, wir im Kern mit jedem Code, der FP anwendet nicht viel verstehen. Es ist wie immer schön den Blog hier zu lesen und darüber nachzudenken, wie es in der freien Wirtschaft aussieht.
Leider muss ich feststellen, dass das Ego mehr zählt als der Nutzen. Wir können also unseren Kunden gegenüber ehrlich sein, wenn er sich nicht auskennt und ihm Funktionalität liefern, die jeder Versteht (explizit) oder ihm etwas liefern, das nur eingeweihte Verstehen (implizit). Und hier schließe ich die Paradigmen erst einmal aus.
Welchen Grundwortschatz und welche Techniken dürfen wir denn als Grundvoraussetzung ansehen und welche sind schon gehobenes Talent? Also Top10 in der Profiliga?
Leider bildet unsere Ausbildung auch nicht angemessen dieses Wissen ab. Kunden können nur auf etwas Wert legen, das sie kennen. Woher sollen sie also wissen was Qualität ist. Gleiches gilt für den Prorammierer? Woher soll er wissen, was Qualität ist? Wenn er die Einsicht dazu nicht hat, oder nicht bekommen will.
So ist das mit der Erleuchtung. Erst wenn man sie besitzt, weiß man was man davon hat.
Und nun bin ich am Ende angekommen. Was ist denn die Erleuchtung in der Softwareentwicklung? Ist es Clean Code, oder findet sich morgen doch noch etwas Neues?
Wer ist einem näher als man selbst? Ich bin junge 31 Jahre und hab schon soviel Egoismus in dieser Welt gesehen. Ich glaube, das ist das eigentliche Problem. Seinem Selbst abzusagen um lieber das zu tun, was andere für richtig halten.
Wenn von der anderen Seite keine Forderung zur Qualität kommt und ich selbst nicht in der Bringschuld bin, das Projekt später zu pflegen zu ändern usw ... ich hab sachen erlebt.
Also was ist explizit und was implizit?
Was dürfen wir vorraussetzen und was nicht?
Ralf, um deine Frage zu beantworten: Ich brauche keine neuen Mittel. Sie können mir das Leben aber erleichtern. Ich Programmiere gerne mit F#. Nicht weil es FP ist, sonder weil es mir Spaß macht. Ob ich jemals damit was produktives damit mache ist ungewiss. Im Moment ist es Python, und das tut mir schon irgendwie weh, weil ich den Compiler liebe ;)
Um noch auf Golo einzugehen. Sollten die GoF Patterns zum Grundwortschatz gehören?
@ Rainer: IMHO auf jeden Fall #GoF.
Vielleicht nicht unbedingt jedes bis in letzte Fitzelnchen, aber die grundlegenden wie Singleton, Factory, Strategy, Template & Co schon.
@Golo: Thema Kindererziehung: Leider die falsche Analogie. Die richtige ist: Kommunikation.
Code ist nicht nur Anweisung für einen Computer, sondern immer auch Mitteilung an den Nächsten.
Code ist also ein Kommunikationsmittel zwischen Menschen. Und bei der Kommunikation gilt: der Sender muss sich um den Empfänger kümmern.
Du bemühst dich ja um gute Vorträge. Warum? Rede doch einfach daher, wie dir der Schnabel gewachsen ist. Warum diese Mühe? Weil du natürlich begriffen hast, dass es auf dich als Sender ankommt.
Dasselbe gilt für Code. Das steckt in dem Spruch: "Code wird öfter gelesen denn geschrieben." Aber er wird meist nur geschrieben, als würde er nur geschrieben, nicht gelesen.
Diese Funktion von Code als Kommunikationsmittel macht es ja so schwierig. Da sitzen Entwickler dran, die gerade eben nicht andauernd mit Menschen kommunizieren wollten... Und sind dazu verurteilt, es den ganzen Tag zu tun. In der Teamdiskussion und dann auch noch mit Code? Puh... das schmeckt natürlich bitter. Hilft aber nix.
Strategy Pattern: Ja, ich bin nicht so konsequent gegen switch oder if/else. Und ich kann dir Problemstellungen zeigen, in denen auch du sagen wirst, dass ein switch einfach einfacher zu lesen ist.
Patterns sind auch nur ein Hammer. Also nicht alles zu Nägeln machen. Experte sein heißt, auch mal die Finger von einem Tool zu lassen.
Neues Lernen und Verständlichkeit sind orthogonal. Neues lernen, damit ich verstehe, was mein Kollege programmiert hat? Eher nicht.
Neues lernen, weil ich damit ein Problem einfacher lösen kann (aber trotzdem das Neue nicht zwanghaft einsetzen muss), das ja.
Wichtige Erkenntnis: Kenntnis muss nicht zum Einsatz kommen.
Auch das ist sicher eine Einsicht, die du als Referent gewonnen hast. Es geht im Vortrag darum, eben nicht alles rauszulassen, was du weißt.
Die Lehre ist in der Pflicht, sich verständlich zu machen. Ebenso ist Code in der Pflicht, sich um Verständlichkeit zu bemühen. Tut er das nicht, haben wir Verhältnisse, wie wir sie eben haben.
"Einfach" oder "verständlich" ist natürlich relativ. Wenn Andreas und Sergej sich in Communities bewegen, die das, was sie da produziert haben, auf Anhieb verständlich finden, dann ist ja alles gut.
Indem sie aber ihren Code veröffentlichen, tragen sie einen Verständlichkeitsanspruch an die große Community heran.
Dem - sorry to say - werden sie aber nicht gerecht.
Wenn die Überschrift jeweils gewesen wäre, "Schaut, was man machen kann!" So sieht legacy code aus. Oder so sieht Code aus, der lambdas ausreizt. Dann wäre ich nicht so darauf angesprungen.
Doch in beiden Fällen ist der Anspruch, dass der Code verständlich ist. Verständlich für die große Allgemeinheit. Einmal implizit (dotnetpro), einmal explizit (Blog).
Das (!) passt nicht, finde ich.
Was nicht heißt, dass man sich nicht mit lambdas noch mehr auseinandersetzen sollte.
@Rainer: " Abstraktion soll uns auf ein höheres Niveau heben ohne dabei Details wegzulassen."
Hm... ich dachte immer, das Gegenteil sei der Fall. Abstraktion bedeutet, eben Details wegzulassen. "Amsel" als Abstraktion eines Vogels, den ich draußen grad sehe, hat viiiiel weniger Details als die "Amsel-Instanz" selbst.
"Leider muss ich feststellen, dass das Ego mehr zählt als der Nutzen. Wir können also unseren Kunden gegenüber ehrlich sein, wenn er sich nicht auskennt und ihm Funktionalität liefern, die jeder Versteht (explizit) oder ihm etwas liefern, das nur eingeweihte Verstehen (implizit)."
Versteh ich nicht. Willst du behaupten, ich hätte gesagt, man solle seinen Code so schreiben, dass ihn Laien verstehen? Das kannst du doch nicht wirklich rausgelesen haben.
"Welchen Grundwortschatz und welche Techniken dürfen wir denn als Grundvoraussetzung ansehen und welche sind schon gehobenes Talent? Also Top10 in der Profiliga?"
Immer wieder eine gute Frage. Und die Antwort ist ständig im Fluss.
lambda Ausdrücke gehören aber heute immer noch zum "gehobenen Wissen". Ist so. Da kannst du den Kopf schütteln, wie du willst. Dito Iteratoren. Das denke ich mir nicht aus, sondern ist meine Erfahrung mit Hunderten Entwicklern jedes Jahr, die ich bei Vorträgen, Beratungen und Seminaren spreche.
"Seinem Selbst abzusagen um lieber das zu tun, was andere für richtig halten."
Wie kommst du denn da drauf?
Nur weil ich in der Kommunikation auf den Empfänger achte, gebe ich mich doch nicht selbst auf. Und tue auch nicht einfach, was andere für richtig halten.
Es geht auch nicht um richtig oder falsch, sondern darum, was funktioniert.
Herr Polke kann sich auf den Kopf stellen und mit den Beinen strampeln und über das Unverständnis der Welt klagen, wenn die Botschaft, die in diesem Bild steckt (http://bersarin.files.wordpress.com/2010/06/sigmar-polke-moderne-kunst-1968_72dpi.jpg) nicht beim Publikum ankommt. Es hilft nix. Wenn das so ist, funktioniert seine Malerei einfach nicht.
Dito die Produzenten des Codes, den ich par pro toto herausgegriffen habe. Funktioniert die Kommunikation mit dem Nächsten oder nicht?
Andreas weiß wahrscheinlich eher nicht, wieviele Leute seinen Code verstehen. Sergej schon eher. Und wenn er dann zufrieden ist, dass es 10 sind und nicht 100 oder 1000, dann ist das auch ok. Hörte sich nur nach seinem Blogposting nicht so an. Da ging es nämlich um den allgemeinen Wert von TDD. Der soll ja für alle Entwickler gelten. Und er hat ein Beispiel ausgestellt, dass diesen Wert verdeutlicht.
Unser Problem ist aber nicht Funktionalität oder Eleganz. Unser Problem ist Evolvierbarkeit. Die ist abhängig von Verständlichkeit. (Und weniger von Kürze.)
"Ich Programmiere gerne mit F#."
Das ist doch fein. Dein Code muss dann auch nur für F#-Jünger verständlich sein :-)
Ralf, vielleicht erinnerst Du Dich daran, dass wir vor einem Jahr eine ähnliche Diskussion geführt haben?
http://carstendevblog.blogspot.com/2010/04/masematte-und-c.html
Wie kommt es zu Deinem Sinneswandel?
@Carsten: Ich sehe keinen Widerspruch zwischen dem, was ich damals in den Kommentaren zu deinem Artikel geschrieben habe.
Damals wie heute vertrete ich den Wert der Verständlichkeit.
Damals wie heute bedeutet das nicht, dass ich keine Spezialfeatures einer Plattform einsetzen sollte.
Ich habe kein Problem mit lambdas per se. Die Erotik bei Sergejs Code entsteht durch Art und Häufung ihres Einsatzes.
Er setzt ja nicht nur lambdas ein, sondern arbeitet mit einer higher order function. Und das auch noch auf einem Problem, in dem eine Hierarchie steckt, die nicht offensichtlich ist.
Hier ist sie deutlich zu sehen: "2+(3*(4^5))"
Hier ist sie nicht deutlich zu sehen: "2+3*4^5"
Und in dem Code ist sie auch nicht zu sehen. Im Gegenteil! Sie nicht zu zeigen, war geradezu Absicht.
In Summe ist dann erotische Programmierkunst entstanden.
Wenn neun von zehn Entwicklern diesem Code nicht folgen können ist das für mich leider einmal mehr ein Hinweis darauf, dass wir hierzulande auf dem Softwareentwicklungssektor einfach hinterher hinken.
Die Ausbildung in der Software-Entwicklungsbranche ist hierzulande nicht so gut wie sie sein sollte. Du twitterst doch selbst öfters über Universitäten, die mehr und mehr damit beginnen ihren Studenten Functional Programming zu lehren.
Wie weit möchtest du denn gehen? Sollen wir lieber wieder
List GetAddresses(List customers){
List addresses = new List();
for(int i = 0; i < customers.Count; i++){
addresses.Add(customers[i].Address);
}
return addresses;
}
statt:
IEnumerable GetAddresses(IEnumerable customers){
return addresses.Select(customer => customer.Address);
}
schreiben?
Ich denke nicht, dass das der richtige Weg ist. Meiner Meinung nach sollten wir lieber dafür sorgen, dass wir hierzulande wieder innovationsfreundlicher, nicht innovationsfeindlicher werden.
Vielleicht schafft es dann auch mal eine deutsche Firma zum nächsten twitter, facebook oder github zu werden.
Sorry, beim Posten, wurde der Code teilweise zerrissen. Ich bin aber guter Dinge, dass die Leser hier den Beispielen trotzdem folgen können.
@Christoph: Ich versteh nicht, dass du - wie andere - mir schon wieder vorwirft, ich sei innovationsfeindlich.
Wer auch nur ein wenig meine Arbeit verfolgt (was ja nicht schwer ist), der muss wissen, dass nichts ferner meiner Einstellung sein könnte.
Linq ist cool. Lambda expressions sind cool. Dynamische Programmierung ist cool. Alles super. Schöne Tools.
Die man einsetzen kann - aber nicht muss. Und wenn man sie einsetzt, dann in rechter Weise. D.h. im Rahmen von Prinzipien und Werten.
Ein Schwert aus Stahl ist besser als eines aus Bronze. Beide brauchen aber Techniken und Ethik drumrum, um sie zu bestem Nutzen einzusetzen.
Dafür steht bei der Softwareentwicklung z.B. die Clean Code Developer Initiative.
Der geht es z.B. um Korrektheit und Evolvierbarkeit. Sie definiert eine Reihe von Prinzipien und Praktiken, wie man die herstellt.
Andreas hat davon nichts angewandt. Es gibt also keinen Verlass, ob sein Code korrekt ist. Und das er schlecht verständlich/evolvierbar ist, kann man auf einen Blick sehen. Namenskonventionen, SLA, SRP, SoC: alles nicht angewandt.
Und bei Sergej, dem hier von dir und andere so in Schutz genommenen? Tja, welche Prinzipien und Praktiken hat er befolgt?
Er hat Tests. (Die sehen wir nicht, aber das glauben wir ihm.) Und er hat nach TDD entwickelt. Auch schön.
Und sonst? Er hat Technologie ausgereizt. Das ist für sich genommen aber keine Tugend. Sorry. Nicht bei Clean Code und nicht bei Clean Code Developer oder bei Code Complete oder woran man sonst in Bezug auf Softwarequalität "glauben" mag, steht irgendetwas davon, dass man Technologie ausreizen solle, um höherer Qualität zu erzielen.
Die Eleganz im Code durch (!) Technologie erkenne ich ja an. Wunderbar. Lass uns über die Vorzüge von Lambdas & Co bei einem Bier reden. Ein Gespräch über Erotik in der Softwareentwicklung... :-)
Aber solange der Code das fundamentale Prinzip der SoC nicht beherzigt... solange versinke ich nicht in Ehrfurcht.
Die Aufgabe "Math. Ausdruck berechnen" zerfällt ganz offensichtlich in mindestens zwei unterschiedliche Aufgaben, die ich nicht nur Responsibility, sondern sogar Concern nenne, weil sie so verschieden sind.
Da ist einmal die Stringanalyse, die Grammatik. Und da ist die Berechnung.
Für Verständlichkeit und Evolvierbarkeit ist es wichtig, diese Trennung im Code sichtbar zu machen. Wer das nicht tut, der mag immer noch elegant sein, aber eben nicht verständlich.
Und wenn ein Design-Vorgehen (hier: TDD) das nicht befördert, dann ist es nicht per se schlecht, aber bleibt hinter seinem Anspruch zurück.
Sergejs Lösung funktioniert. Sie ist korrekt. Sie ist technisch elegant. Bravo!
Aber über diesen Anspruch an Software sollten wir doch mal hinaus kommen, oder? Funktionalität und Eleganz waren schon Thema in den 70ern. Korrektheit ist dann in den 90ern als wichtiges Thema dazu gekommen.
Und im neuen Jahrtausend ist es hohe Zeit, dem auch noch die Evolvierbarkeit hinzuzufügen - sogar als stärkere Kraft.
Eignung, Korrektheit, Evolvierbarkeit: darum geht es. (Eignung=Erfüllung der funktionalen und nicht funktionalen Anforderugen)
Eleganz ist was für Turmspringer, Tänzer oder den Opernball.
Eleganz außerhalb von Prinzipien, die für Eignung, Korrektheit und Evolvierbarkeit sorgen, sollte uns nicht interessieren.
PART1:
"@Rainer: " Abstraktion soll uns auf ein höheres Niveau heben ohne dabei Details wegzulassen."
Hm... ich dachte immer, das Gegenteil sei der Fall. Abstraktion bedeutet, eben Details wegzulassen. "Amsel" als Abstraktion eines Vogels, den ich draußen grad sehe, hat viiiiel weniger Details als die "Amsel-Instanz" selbst."
Für den Kontext (und damit das Verständnis) wichtige Details dürfen nicht weggelassen werden. War ungenügend von mir ausgedrückt, geb ich dir Recht!
""Leider muss ich feststellen, dass das Ego mehr zählt als der Nutzen. Wir können also unseren Kunden gegenüber ehrlich sein, wenn er sich nicht auskennt und ihm Funktionalität liefern, die jeder Versteht (explizit) oder ihm etwas liefern, das nur eingeweihte Verstehen (implizit)."
Versteh ich nicht. Willst du behaupten, ich hätte gesagt, man solle seinen Code so schreiben, dass ihn Laien verstehen? Das kannst du doch nicht wirklich rausgelesen haben."
Nein, das habe ich nicht gemeint. Ich habe es so gemeint, wie du es bereits in einem vorherigen Kommentar gesagt hast. Der Kunde als Auftraggeber wird das Stück Software das wir als Dienstleister Produzieren zu einem späteren Zeitpunkt einem anderen Vorlegen. Mein Gedanke war der gleiche wie deiner. Code als Kommunikation: Die anderen Dienstleister müssen es auch lesen. Warum entscheide ich mich denn Technologie zu nutzen die ich gelernt und verstanden habe, egal wie komplex sie ist? Vermutlich weil es für mich einfacher ist sie zu nutzen, oder weil ich dann "Besser" bin. Daher mein Bezug zum Ego.
Lambdas gehören zum gehobenen Wissen? Dann bewege ich mich wohl eher in gehobenen Kreisen. Aber ich bin auch nicht Freiberuflich unterwegs. Was ich aber nicht verstehe: Warum die so wenige kennen sollen. Ich meine: Das Konzept an sich ist einfach. Delegates und anonyme Delegates kennt doch in C# auch jeder. So weit ist es dann zu den Lambdas auch nicht mehr. Lesen diese Entwickler gar keine Blogs, oder Nachrichten? Sind sie so desinterresiert an dem Fortschritt, den sie ja selbst als Produkt verkaufen?
""Seinem Selbst abzusagen um lieber das zu tun, was andere für richtig halten."
Wie kommst du denn da drauf?
Nur weil ich in der Kommunikation auf den Empfänger achte, gebe ich mich doch nicht selbst auf. Und tue auch nicht einfach, was andere für richtig halten."
Es geht nicht meiner Meinung nach nicht um die verständliche Kommunikation. Es geht noch immer um die eigene Meinung, das hat mit Kommunikation die richtig gesendet und empfangen wird nichts zu tun.
Wenn ich der Meinung bin F# ist besser als C# (rein fiktiv, das ist nicht wirklich meine Meinung, mir gefallen bestimmte Aspekte in C# besser und die meisten andere in F#) und 9 meiner Teamkollegen sind es nicht und ich ihnen auch darlegen kann was daran hilfreich ist. Deshalb habe ich den Bezug zur Erleuchtung gemacht. Ein Kollege der meine Worte versteht und bei dem sie ankommen, der ist noch lange nicht erleuchtet. Kommunikation an sich ist doch implizit Fehlerbehaftet. Nur die subjektive Erfahrung des anderen kann dazu führen "etwas Neues" zu verwenden. Die Neugier leitet ihn da hin. Warum also sind so wenige Neugierig? Oder anders. Warum muss ich immer was neues lernen? Brauch ich doch nicht. Warum gibt es aber immer wieder neue Technologien? Einfach um Geld zu verdienen, weil ein neuer Markt daraus ebntsteht, oder weil es sich wirklich einer bestehenden Problematik widmet. subjektiv und objektiv hin oder her... was bitte ist denn in der SW objektiv? (Sollte kein Kalauer sein im Bezug auf OOP).
PART2:
Um wieder auf den Kern zu kommen: Evolvierbarkeit. Verfasse doch mal als Essenz aus deinem Wissen neben deinen Kolumnen, Wikibeiträgen, Forendiskussion ein Buch, die deine Meinung darstellt, wenn du glaubst du kannst damit was bewegen.
Das Problem ist nicht der gute Wille. Evolvierbarkeit kostet etwas. Und solange es keine Qualitätskontrollen gibt, die das überprüfen, wird es immer Entwickler geben, denen das keinen Spaß macht. Ich hab Kollegen die halten Unittests für Zeitverschwendung... denen sind Prinzipien und Praktiken zu wieder, weil sie ihre Freiheit einschränken und unproduktiv sein... ja das Problem der Kommunikation
Kommunikation ... ist halt eben auch nur ein Model. Ich bleib dabei: Die persönlich Vorlieben (also die Subjektivität, die vom Ego getrieben ist) beherrscht unser leben. Wer lediglich die Lehre der Evolvierbarkeit kennt, wird diese wohl gut ausführen. Wer auch andere Lehren kennt, wird wohl eher die bevorzugen, die ihm Spaß macht. Ich kennen kaum Menschen, die sich gerne selbst Kasteien.
Also Ralf, beantworte mir bitte die Fragen:
Warum soll Joe Developer Evolvierbar entwickeln, wenn es a) keiner intern konotrolliert, b) der Kunden die Qualität erst gar nicht beurteilen und somit nicht von extern kontrollieren kann? und c) ihm die Ethik Clean Code keinen Spaß macht?
Warum soll also Joe Developer Evolvierbar entwickeln?
Nicht falsch verstehen. Ich weiß was du mir sagen willst. Aber wie kann ich andere damit erleuchten?
@Rainer: Warum soll ein Entwickler Evolvierbarkeit herstellen?
Lass es mich platt formulieren: Weil Evolvierbarkeit ihm seinen Job erhält.
Ja, am Ende ist es so einfach. Ohne Evolvierbarkeit läuft Softwareentwicklung Gefahr, unwirtschaftlich zu werden. Ich habe Softwarehäuser pleite gehen sehen, weil sie einfach nicht mehr den Kundenwünschen entsprechen konnten.
Es so ausdrücken macht klar, dass wir bei Evolvierbarkeit über etwas reden wie "Alt werden".
Jeder will es haben - aber keiner weiß so recht wie und vor allem scheint es ja auch nicht so dringend. Geht doch heute noch.
Mit 20 hab ich keine Probleme mit 2 Packungen Zigaretten am Tag. Mit 28 hab ich keine Probleme, Nächte durchzuarbeiten. Mit 36 hab ich kein Problem, den ganzen Tag zu sitzen und abends Sport mit der Sportschau zu treiben.
Ein junges Projekt hat auch kein Problem mit seiner Gesundheit/Evolvierbarkeit. Die Strukturen sind noch nicht so groß und noch nicht so verflochten, da geht immer irgendwie was. Und die Motivation ist auch noch hoch und kompensiert viel.
Aber nach 2 Jahren ist die Luft raus. Immer. Ich kenn kein Projekt das dann nicht merkt, dass es nicht mehr so einfach ist mit dem Einpflegen von Neuem.
Und so ist es mit 40+ Jahren beim Menschen. Die Brille wird dann akzeptiert, dann wünscht man sich den Fahrstuhl für die Whg im 4. Stock und mit 60 kann man dem Bus nicht mehr hinterherlaufen (und braucht das auch nicht mehr, oder?).
Mit 80+ ist die Schere dann weit offen: die einen sind dement und immobil im Pflegeheim, die anderen sind noch geistig rege, aber der Körper will nicht mehr, und wieder andere spielen jede Woche noch fleißig Tennis.
Schicksal? Kaum. Jedenfalls nicht in dem Maße, wie uns die Glaubenssätze übers Altern vormachen wollen. Dazu gibt es auch schon Studien. Wie du alterst, wie du im Alter bist, bestimmst du zu einem großen Teil selbst.
Nur wer tut das bewusst? Ist noch so weit weg, wenn man 33 ist.
Weiter bei Teil 2...
Teil 2:
Dito bei der Software. Warum soll ich mich hier und heute um Evolvierbarkeit kümmern? Merk ich doch nix davon. Und mein Chef hat mich auch nicht mehr lieb dafür.
Das ist aber ein Denken, das erstens durch Kurzsichtigkeit gespeist wird und zweitens durch ein ideal lokaler/temporärer Effizienz.
Es herrscht der unbeirrbare Glaube, dass eine Summe von kleinen Effizienzen das Große Ganze auch effizient machen würde.
Das ist aber eine Fehlannahme. Auch noch eine leicht zu beweisende. Mach das mit den widerständigen Entwicklern: http://alistair.cockburn.us/Airplane+game
Da kann jeder spüren, dass es für das Ganze uninteressant ist, ob ein Einzelner schnell ist.
Damit ist dem Argument, Unit Tests würden ja vor allem langsam machen, der Wind aus den Segeln genommen. Selbst wenn es so wäre (was ja noch zu beweisen ist), wäre das nicht schlimm.
Für mehr theoretischen Hintergrund hier ein Sachbuch: http://www.amazon.de/What-Thing-Called-Theory-Constraints/dp/0884271668
Die Frage ist also zu allererst: Ist jmd daran interessiert, das Ganze der Softwareproduktion zu optimieren?
Ist er daran interessiert, Geld heute und in Zukunft (!) zu verdienen? Menschen heute und in Zukunft (!) zufrieden zu machen?
Wer daran interessiert ist, der muss dann im Sinne der "Gesetze" von Produktionsflüssen überlegen, welches passende Metriken sind. Denn am Ende bekommt man immer nur Leistung von Menschen im Rahmen dessen, was irgendwie gemessen/honoriert wird.
Wenn vor allem honoriert wird, dass 1. Leute ordentlich in die Tasten hauen und 2. dass irgendwie Code zu Kunden geht, dann bekommt man nur das:
Menschen die an Keyboards sitzen und irgendwas tun, um geschäftig auszusehen. Und irgendwelcher Code, der zum Kunden geht.
Ob das, was sie an den Keyboards tun, ein Bugfix ist (also kontraproduktive Nachbesserung) oder nicht, wird nicht gemessen.
Also: jeder kann für sich selbst entscheiden, was er will.
Wenn ich für Evolvierbarkeit eintrete, dann setze ich voraus, dass meine Empfänger den Wunsch haben, heute und in Zukunft (!) Geld zu verdienen und heute und in Zukunft in Zufriedenheit zu arbeiten. (Zur Zufriedenheit gehört dabei, dass sie stolz auf ihre Arbeit sind. Dass ihre Arbeit ihnen Bedürfnisse wie pers. Wachstum, Bedeutung, Verbindung mit anderen, Beitrag zu einem Zweck erfüllt.)
"Also: jeder kann für sich selbst entscheiden, was er will.
Wenn ich für Evolvierbarkeit eintrete, dann setze ich voraus, dass meine Empfänger den Wunsch haben, heute und in Zukunft (!) Geld zu verdienen und heute und in Zukunft in Zufriedenheit zu arbeiten. (Zur Zufriedenheit gehört dabei, dass sie stolz auf ihre Arbeit sind. Dass ihre Arbeit ihnen Bedürfnisse wie pers. Wachstum, Bedeutung, Verbindung mit anderen, Beitrag zu einem Zweck erfüllt.)"
Wenn jeder selbst entscheidet, dann halt keine Effizienz. Der Weg des geringsten Wiederstandes! Ralf, ich spreche aber leider nicht mit Gleichgesinnten. Gleichgesinnte, die umherirren sind die verschwindende Minderheit, sie zu für CCD zu begeistern ist ein leichtes. Evolvieren kann ich auch den letzten Code ... Die Frage ist nur wieviele Resourcen dafür eingesetzt werden. Es geht also wie immer um Nachhaltigkeit, Wirtschaftlichkeit und damit den Resourceneinsatz die in Zeit*Geld gemessen wird.
Vielleicht ist aber CCD eine so hohe Kunst, die zu lehren, zu verstehen und anzuwenden nur für ein paar wenige möglich ist? Ich verstehe all deine Argumente, weil ich entsprechende Erfahrungen gemacht habe und gleichgesinnt bin.
Ich sehe aber noch immer nicht, wie ein anderer Softwareentwickler der dir feindlich gegenübersteht durch Fliegerfalten seine Meinung ändert.
Du musst davon ausgehen, das mein Gegenüber nicht über Nachhaltigkeit nachdenkt. Der nichts von all dem versteht oder verstehen will, was du mir erklärt hast. Immerhin sprechen wir von Leuten, die sich nicht mit Lambdas auskennen und für Neues wohl eher nicht so empfänglich sind. Vielleicht sind sie es und wollen es bei dir lernen. Prima, du hast ihnen geholfen. Vielleicht kommen sie aber nicht zu dir, weil es Zeit- und Geldverschwendung wäre und sie es sowieso nicht interessiert. Ich als grundsätzlich Neugieriger Mensch bin offen für Neues und habe den Nutzen schnell erkannt.
Aber wie bekomme ich den nicht gewillten, nicht neugierigen, vielleicht sogar persönlich in seiner Meinung angegriffenen, feindlichen Entwickler dazu etwas zu probieren, an dem er gar nicht interessiert ist? Das ist mir immer noch nicht klar! Ich hab bis heute keine Methode gefunden, die andere mit meinem Wissen erleuchtet. Ihm vorzuschlagen Flieger zu falten wird ihn für die Praktiken des CCD nicht bewegen können. Ernsthaft ... Jemandem der Effizienter werden will, kannst du damit begeistern, weil er offen ist, neue Methoden und Einsichten zu erhalten um nach endlich den heiligen Grahl zu finden, den er so lange sucht.
Ich selbst, der gläubige gut Gesinnte, bin kein Pädagoge, der das Material aufbereiten und lehren kann. Wer Lehrt also und kann auch noch beweisen? Das Problem in unserer Monetären Gesellschaft ist doch: Was nicht Messbar und beweißbar ist ... ist Esotherik oder Scharlatanerie.
Wie schaffst du es also, einem Grundsätzlich desinteressierten, evtl. feindlich eingestellten Menschen deine Ansichten näher zu bringen? Oder kannst du ihm Maßzahlen zeigen, die ihn aufgrund der Tatsachen so überwältigen?
weiter bei Teil 2
Teil 2
NOCHMAL: Ich versteh das alles was du mir sagst, ich bin gäubig und gut Gesinnt! Wie kann aber die Kommunikation des CCD die für mich ersichtlichen Fakten (die du mit Zahlen hinterlegen musst) von esotherischem Ideentum in eine Wissenschaft umwandeln?
Entscheider tun etwas, was sie messen können, oder nicht? Der Alltagsentwickler (so meine Erfahrung) tut das, was man ihm sagt: Die Funktionalen Aspekte erfüllen, wenn Sicherheit dazu gehört, tut er es. Wenn Evolvierbarkeit gefordert wird, tut er es, wenn ein Pflichtenheft im sagt was dafür zu tun ist. Und selbst die Sicherheit ist noch nicht überall angekommen. Zumindest spiegelt sich das nicht immer in automatisierten Tests wieder.
Deine Forderung nach Evolvierbarkeit und Nachhaltigkeit ist hoch berechtigt. Aber ich sehe noch nicht wie deine Kommunikation den Ungläubigen überzeugen kann, von denen gibt es mehr als genug auf diesem Planeten. Warum gibt es immer noch Atomstrom? Warum beziehen noch so viele Menschen ihren Strom bei EON und Konsorten? Warum nehmen wir degenerative Nahrung zu uns? Warum, warum, warum? Ich war auch mal gierig und strebsam, nach Profit.
Vielleicht ist der persönliche Schmerz bei besagter Mehrheit, um endlich mit Nachhaltigkeit anzufangen noch nicht Groß genug. Wie kannst du, als Prophet also, den Glauben an die Nachhaltigkeit verbreiten, dass ihn auch noch der letzte versteht?
Welche der vielen Software Glaubensrichtungen sind nachhaltig, und welche nicht? Welche werden angewendet wie oft angewendet? Wie kann ich einen Andersglaubenden bekehren? Vielleicht befinde ich mich in einem Umfeld, das mir nur wenig positive Beispiele zeigt. Ich weiß es nicht. Vielleicht sollten wir alle mit Nachhaltigkeit anfangen und nicht soviel Neues haben wollen! Eine Frage bleibt ja auch noch: Ist CDD Unterhaltung oder ein Werkzeug? Soll es also Spaß machen oder die Arbeit verrichten? Kann es beides? Oder gibt es Aspekte, die andere nicht als angenehm empfinden könnten? Wenn ja, warum ist das so?
@Rainer: Wenn dein Menschenbild ist, dass der unmotivierte Entwickler tut, was du ihm sagst, dann sag ihm halt, was er tun soll.
Wenn du ein Menschenbild hast, in dem einer tut, was Schmerz vermeidet, dann zeig ihm, wie CCD usw. Schmerz vermeidet.
Definition von Schmerz: Alles, was nicht dem Soll entspricht, also nicht den Werten genügt, die laut Metrik erreicht werden sollen.
Daraus folgt: Willst du schmerzsensible Entwickler in eine Richtung bringen, dann musst du passende Metriken haben.
Die heutige Metrik in deinem Unternehmen ist: "Muss schnell irgendwie funktionieren". Mehr nicht.
Und genau das liefern die Entwickler dann. Darauf ziehen sie sich zurück. "Chef, aber wir haben es doch schnell irgendwie hingekriegt."
Was soll der Chef darauf sagen? Nix. Sie haben Recht.
Wenn die Kultur des Unternehmens keine Metrik für "Nachbesserungsaufwand" hervorgebracht hat, dann haben Entwickler dafür keine Schmerzrezeptoren ausgebildet, dann kannst du dir den Mund fusselig reden bzgl. Unit Tests.
Wenn die Kultur keine Metrik für "Evolvierbarkeit" hervorgebracht hat... dann gibt es dazu keine Schmerzrezeptoren.
Das ist, als würdest du zu Blinden über Farbe sprechen. Es gehört nicht zu ihrer Weltwahrnehmung, es hat nicht mal Relevanz. Ampel rot oder grün? Keine Relevanz für einen Blinden. Schlechte Evolvierbarkeit ohne Metrik? Keine Relevanz für Entwickler.
Und woher kommen Metriken? Von der Führung.
Der unmotivierte Entwickler wird nichts ohne Vorgabe durch die Führung tun. Da kannst du dir den Mund fusselig reden. Und Führung drückt sich dem unmotivierten durch Metriken aus.
So einfach ist das Rezept: Du bekommst auf längere Sicht immer Entwickler, die den Metriken entsprechen.
Das trifft für die Codequalität zu und für ihre Motivation. Motiviert sind Menschen nur in einer Kultur, die Motivation in irgendeiner Form wahrnimmt (Metrik) und honoriert.
@Ralf: Danke, dass du es nochmal so schön zusammengefasst hast.
Ich denke damit ist alles Explizit gesagt. Das heißt, wer nicht will der hat schon. Ich darf weiter einsamer Indianer spielen und hoffen die anderen irgendwann zu erleuchten ;)
@Rainer, es ist interessant, wie die Frage "Erotik oder Porno" zu der Frage "Wie bekehre ich die Ungläubigen" geführt hat. Du bist leider nicht der einzige, der sich deswegen wie Don Quijote fühlt...
Ich habe gehofft, das Thema in Karlsruhe ansprechen zu können, aber wie ich sehe, weder du, noch Ralf kommt hin. Schade.
Christina
Kommentar veröffentlichen
Hinweis: Nur ein Mitglied dieses Blogs kann Kommentare posten.