Logo

Empathic Code

von

Twitter Spam Loswerden

Ich habe von Zeit zu Zeit auf Twitter ein ganz klassisches Problem: Spam.

Twitter Spam

Diesen loszuwerden ist sehr ätzend, besonders wenn man, so wie ich, nur das Webinterface benutzt. Dort muss man jeden Tweet einzeln anklicken und auf "Block User" gehen. "Das geht doch sicher besser", dachte ich mir.

Geht auch besser - mit dem in Ruby geschriebenen Konsolentool "t".

Das Tool erlaubt einen sehr flexiblen Zugriff auf alle Twitter-Daten. Zuvor muss man noch eine Authentifizierung vornehmen und einige Tokens über die Twitter-Api generieren. Aber das ist halb so wild und "t" hilft einem auch dabei.

Der folgende Befehl gibt Zugriff auf alle Nachrichten, die öffentlich sind und in denen mein Name vorkommt:

$ t mentions

Genau das trifft auf den Spam ja zu. Dieser ist immer direkt an mich gerichtet. Leider kann ich nun nicht einfach alle diese Nachrichten blockieren - immerhin bekomme ich ja auch sinnvolle Nachrichten auf diesem Wege übermittelt. Auffällig ist das Muster, das die Spammer verwenden um das Spam-Schlagwort "followers" zu obfuskieren. Einfach ein paar Punkte dazwischenmogeln - schon kann man automatisch spammen, wie es scheint. Aber das kann ich auch rumdrehen:

$ pattern=$(python -c "print '\\.?'.join([c for c in 'followers']) + '?'")

Der Code ist simpel. Er führt direkt ein Python Kommando aus. Dieses trennt alle Buchstaben des Wortes followers heraus und setzt es wieder zusammen, indem \.? dazwischen geklebt wird. Das so entstehende Muster wird einfach ausgegeben und in einer Variable namens pattern in der aktuellen Shellsitzung gespeichert:

$ echo $pattern
f\.?o\.?l\.?l\.?o\.?w\.?e\.?r\.?s?

Inhaltlich steht da lediglich: "followers" oder "follower" - und hinter jedem Buchstaben kann ein Punkt stehen oder auch nicht. Mit diesem Pattern bewaffnet gehe ich nun auf die Jagd.

$ t mentions -n 100 -l -r > spam.txt

Zuerst packe ich die letzten 100 Mentiones tabellarisch in eine Datei namens spam.txt. Die Operation dauert etwas länger und ich möchte erstmal rumprobieren, daher speichere ich das Ergebnis in der Datei zwischen. Danach kann ich mit Hilfe des Patterns die entsprechenden Einträge suchen.

$ cat spam.txt | grep -E $pattern

4...0  May 16 21:59  @fl...m5  ... gain some extra fo.llo.wers
4...1  May 16 21:59  @Cr...an  ... gain some extra fo.llo.wers
4...8  May 16 21:59  @gu...Wi  ... gain more fo.llo.wers
4...0  May 16 21:59  @ch...vi  ... get f.ol.lo.wer
4...2  May 16 21:59  @mo...ua  ... get more f.ol.lo.wer

Bei mir hat das Pattern geholfen und ich hatte nach diesem Schritt nurnoch Zeilen mit Spam übrig und keine echten Personen. Gegebenenfalls sollte das Pattern aber hier verfeinert werden, damit keine echten Follower blockiert werden.

Danach filtere ich die Benutzernamen heraus. Dazu habe ich mir das tabellarische Output zunutze gemacht:

$ cat spam.txt | grep -E $pattern | cut -d " " -f -7

@flang...tm5
@Cross...ian
@guvac...rWi
@chich...Avi

Und die schicke ich jetzt an t zum blockieren:

$ cat spam.txt | grep -E $pattern | cut -d " " -f 7 | xargs t block
Run `t delete block @flang...tm5 @Cross...ian @guvac...rWi @chich...Avi ...
to unblock.

Sehr nett, t, aber das werde ich sicher nicht tun.

Das gesamte script ist also:

p=$(python -c "print'\\.?'.join([c for c in 'followers'])+'?'")
t mentions -n 100 -l -r > spam.txt
cat spam.txt | grep -E $p | cut -d " " -f 7 | xargs t block

On Patterns

TL;DR

Looking into the Flask web framework for python I discover some bewildering code that makes me reflect about patterns. I find the focus on design patterns insalubrious to a healthy code base, and explain why I think so, using the Model View Controller Pattern (MVC) as an example. I see this linguistic code pollution as the main source of bad code.

Make up

Flask used to be my favorite web framework for a while now, because it allows you to create web apps without much noise, much like Sinatra does in ruby, but in the last couple of days my heart has started drowning in doubt. It appears that flask just hides the ugly away by wearing too much makeup. On the surface there are a couple of kawaii-esque decorators; yet if you look closely, you will start to notice how the application in the background consists of a massive 2000loc file that just does too much and has no clear separation of concepts and concerns. The testability is crappy, since a lot of stuff is being imported from the main module. This in itself isn't too bad, but the problem is that many aspects of the application are imported to be global, partially mutable state, that can't be injected from the outside. This significantly reduces readability, and creating or requesting app contexts in the tests is tedious, noisy and error prone - just what you hope not to receive when you settle for Flask. I should have listened to the signs a while ago. What buggs me most right now is this:

http://flask.pocoo.org/docs/tutorial/views/

Before I explain why, let's step away from Flask itself for a minute, because I really still love flask and don't want to make this article a flask bashing. In fact, this very simple website is built with Flask. But to me, there is another very fundamental problem in the way: Patterns.

Design Patterns

Patterns, as is often claimed, are ment to communicate with other people. In my experience they only show up as a replacement for a conversation. They lead people to consent on very implicit definitions of what something is or what it should do. These definitions become the assumptions of the people working with the code and in fact create a hidden profile (make sure to have a look at the sources).

In the document, they describe the "views". This is another very good example of how simple patterns might be misunderstood, rendering those patterns not so simple after all. Of course they are just patterns and effectively you can invent your own and call your stuff whatever you like to call it, but then at least don't leak the pattern names into your code or your docs.

MVC? More like WTF

Let's reconsider for example MVC. It starts out with the M - the model. The funny thing is, that with MVC the application never starts with M, but with C - the Controller (except for when you use something crazy like ASP.NET Derp-Forms, where everything starts with a view). The routing mechanism is fired up by the webserver and receives input, that is a requested resource's path. Depending on that path the MVC framework will decide which controller handles the whole thing (i.e. 'routing'), pass it to the controller method. The controller will invoke the model and the model will help to generate and populate the view. The view is then returned.

There are many parts where understanding this can go wrong, the first part being that this should actually be CMV and not MVC to account for the order of calls. In old java diagrams the arrows tend to point in both directions between the boxes indicating the components, but for most applications the data flow is quite normally the same - The controller is invoked by a request. The controller then invokes the model and handles it all the data it received. It already did some routing at this point, as it interpreted the path of the request. It then handles all the posted form data or request parameters. Therefore, as Martin Fowler agrees, it should actually be called the input controller:

The presentation part of MVC is made of the two remaining elements: view and controller. The controller's job is to take the user's input and figure out what to do with it.

Controller Confusion

Just to add more confusion, browsing Martin Fowlers patterns yields more distinctive controller patterns, for example:

Also note that a controller and a presenter might or might not be the same thing...

So there you go. The term controller doesn't say anything and is therefore a weasel word. Without further differentiation the intention and shape of a controller won't become clear. The details vary depending on where it sits, when it is called and what it really does. None of these aspects can actually be infered from the term controller. Therefore I would like to promote calling controllers "input controllers", as far as they are the thing that...

Model != Data Model

This distinction might sound arbitrary, but bear with me - I have seen a lot of people mistake a controller for the thing that "controlls" the application and therefore should make decisions about what goes where; thus putting tons of conditional logic in it, but I'd argue that the controller is an input controller and should only decide on what path input arrives, what calculations are done and what view gets returned, none of which is really a conditional thing.

The actual logic - deciding whether a user is logged in, checking the sorting order of returned lists, generating news articles, and so on, are all handled in the parts that are called the model. Here the most amazing fallacy appears to come from: for most people the term model is a synonym for data model, thus being some form of direct representation of the data in a (relational) database.

I would like to put forward that a model is not only a declaration of or schema for a certain structure, but that a valid model also contains operations and processes. All things that are conditional are therefore parts of the processes within that model. "Model" appears to be a synonym for data model, therefore often controllers have a direct dependency on repository classes and already start to deal with data filtering, cleaning and retrieving rows and columns, projecting and selecting data from a database - thus rendering the controller a part of the business or logic layer instead of as a part of the overall model.

The distinction between models often includes qualifiers as Domain Model or Anemic Domain Model (a data model). On its own, the term doesn't say much. And no, the DDD book didn't help to make this better.

Views - See for yourself

What is left are the views. These can hardly be mistaken for something else, right? Wrong. The views in my mind should be the XAML or HTML or AWT frames that are being returned, display the data that the controller decided they should publish; but often they are mistaken for viewmodel classes or, as for the hook of this rant, for controller functions. Have a look at the url that I posted above. In the example it states:

Now that the database connections are working we can start writing the view functions.

But the first method already shows what's wrong with the whole conception:

@app.route('/')
def show_entries():
    db = get_db()
    cur = db.execute('''select title, text 
        from entries 
        order by id desc''')
    entries = cur.fetchall()
    return render_template('show_entries.html', entries=entries)

Here, the show_entries function is activated by the app.route decorator. This is essentially creating an entry for the routing table. Note that in python/flask there is no need to put this function into a controller class (it's a "first class citizen" function rather then a method on an object instance). Therefore I would argue, that this function is a controller function. In ASP.NET MVC they would be called Actions. There is no finer granularity in the pattern name, MVC does not say whether the controller is a function, a class or a module, as it is in this case. There is also no mention of the actions.

Here there is no object, as in python the module can house all sorts of things. Of course, it returns a view - which is probably why the authors claim that it is a view function. But this still is exactly what a controller does in MVC.

Entertaining Lies

So, in the abbreviation MVC all three characters are lies. The model does not contain operations, the views are mistaken for controllers and the controllers contain logic. There are two ways to treat this situation. Since patterns are not handled scientifically - there appears to be rough concensus about the hows, but everybody can cook and claim their own - I should describe different points of view here.

If my conception of MVC is right: - The authors got MVC wrong - The views functions are controllers or actions - The pattern is misinterpreted and not helpful to communicate intent or implementation

If the author's conception of MVC is right: - I got MVC wrong - So did Microsoft and many others - The pattern is misinterpreted and not helpful to communicate intent - The functions are views - then what is the template being returned in the end? - If def showentries() is a view, then what, in your mind is 'showentries.html'?

There.

Patterns get in the way

My intention here is not to point out the bad code in Flask or a deficits in the pattern-knowledge of its authors. I love Flask and have a deep respect for the skills and contributions of the people behind it.

Yet this is a perfect example of how patterns can break, if they are forced into the conversation about code. Of course, nowhere on the site the authors claim that they are doing MVC, and might try to weasel out from the discussion - yet calling something a view should not be without consequence. It should mean the same thing to me as it does to anybody else. With patterns I often observe that people name things after what they think a pattern name means, without actually ever looking up the definitions. I have seen this with "Data Transfer Objects", "Data Access Layers", "Anti Corruption Layers" and the pervasive POCO.

The latter is the worst of all. It should mean "object without crazy database dependency, decorators or inheritance when dealing with an ORM or intersystemic calls", but for many people it means "Data Structure", which is a class without functions but a lot of public data. A struct-by-reference really. I am mostly amazed that this distinction (Object vs. Data Structure) never occurs in a discussion with people who claim to have read and understood Robert C. "Uncle Bob" Martins very nicely written book Clean Code. I am really frustrated about these naming decisions that many developers do. To me, the lack of attention to intent and the focus on patterns is what makes code hard to read.

A solution?

What is the solution to this babylonian multiplication of the languages? I don't know. I usually start with what I might call language markers - that is putting tiny hints in my language, so that people may tumble from time to time when discussing these issues. If I say "Model-View-InputController", someone might ask me why I don't just call it "a controller". This is usually where good conversations start with fellow developers. Conversations like that, if held passionately and loudly, can empty whole taprooms full of normal people.

Language Markers

Let's think about more markers. For example, the Controller is the InputController, the Model should capture the business logic, and the views should be the thing that displays stuff. And since in software development we all can make stuff up, I could go over to call this the IDD pattern - input, domain, display. Or how about IIV? For Input, Intent, View? Maybe I will just go with FYP-S, short for fuck your pattern, stupid. I will have to make sure to make a confusing acronym. Or hell, let's maybe call it a ServiceStrategyFactory, just to mess with people. It is a service, since a website provides a service, the functions on the controller are the individual strategies and it creates views (i.e. it renders html), so it's a factory. After all, noone can really define these, so here you go. The FFS Pattern.

I am sorry, I got carried away.

Conclusion

Although it might sound different, I don't see why my opinion should be absolute. I would just like to say that my definition of MVC is biased by my ASP.NET MVC Background and is as good as any other's. Still this renders patterns a poor decision to communicate about or within a codebase, because there are as many understandings of the patterns as there are devs on a project.

I conclude: - Patterns are misleading - Even simple patterns will be misinterpreted - Neither are they good recipes nor is their emergence easily detectable (since their components are not easily defined) - Object oriented patterns are exactly that: Concering Objects - They don't solve anything - Flask is ugly in the background and this misunderstanding of patterns, lack of consistency and arbitrary usage of terms might be some of the reasons why - I still love flask





As you can see, there is no commenting function on this website. If you wish to contribute, please write me an email or message me via twitter. I will add what you wrote to the article manually. This tiny obstacle is there not to censor but to prevent spam and unnecessary trolling.

What might Psychology be, if not Philosophy, and Computer Science, and Bullshit?

Zusammenfassung

Ein interessantes Seminar führt mich in die unkartographierten Bereiche meines Wissens; ich falle in einen Kaninchenbau aus Philosophie und Kognition und entdecke das lustigste Paper aller Zeiten. Der Bachelor nervt immernoch und Philosophie kann ziemlich toll sein.

Prokrastimmierung

Vor Kurzem hatte ich das Gefühl, innerhalb meines Studiums abzudriften. Ich sollte ja eigentlich Psychologie studieren, aber der Informatiker in mir fordert immer öfter Wegzoll und ich muss einfach mal wochenweise sinnlos Software schreiben oder mich mit Algorithmen und Datenstrukturen beschäftigen. Prokrastimmieren nenne ich das, eine Ligatur aus Programmieren und Prokrastinieren, you get the idea.

Als nächstes steht meine Bachelorarbeit an, in dieser soll es wieder um die Kognition beim Programmieren gehen. In meiner ersten Studie habe ich dazu ja bereits einige Vorarbeit geleistet. Zwischenzeitlich hatte ich es aber geschafft, mich wieder mehr auf mein Studium zu konzentrieren. Was ich in dieser Zeit gelernt habe, möchte ich hier dokumentieren; für mich als Tagebuch, für dich als Unterhaltung.

Ein tolles Seminar

Der Titel des heutigen Eintrags mag etwas seltsam gewählt sein. Mein Semester fing für mich im Dezember an (als es eigentlich schon zur Hälfte vorbei war). Da besuchte ich ein Seminar bei Daniel Holt der sich, im breitesten Sinne, mit Lernen und Problemlösen beschäftigt. Dieses heftige Understatement kannst du, lieber Leser, gerne selbst korrigieren, indem du auf den Link klickst.

Daniel hatte zusammen mit ein paar Leuten vom IWR, dem Institut für Wissenschaftliches Rechnen an der Uni Heidelberg, ein interessantes Seminar mit kompliziertem Namen angeboten: "Gedanken und Gefühle in Zahlen – Methoden des Wissenschaftlichen Rechnens in der Psychologie". Der Name ist so lang wie das Programm. Wir diskutierten in vier viel zu kurzen Sitzungen über kognitive Modellierung, die Natur der Kognition und angemessene wissenschaftliche Instrumente zu deren Beschreibung. Dabei wurde auch ein Paper besprochen von Tim van Gelder, mit dem Titel "What might cognition be, if not computation?". Van Gelder greift die vorherrschende Sichtweise an, dass Kognition am besten durch Komputation beschrieben wird und zeigt auf, dass dynamische Systeme und die dafür zu nutzenden Werkzeuge (Differentialgleichungen) angemessener seien, um sich über die Kognition als Solche gedanken zu machen. Das Paper ist gut zu lesen, spannend, durchwachsen und man wird nicht wirklich schlauer davon.

Ich sollte eine Kritik des Papers als Hausarbeit schreiben. Das Ganze hat mich knapp 3 Monate gekostet und ich habe immer noch kein Ergebnis - da ich aber eh nichts von Noten halte, ist mir auch egal was das für eine wird und ich konzentriere mich lieber auf das, was ich dabei gelernt habe. Die möchte ich nun weniger inhaltlich zusammenfassen, als viel eher meinen eigenen, subjektiven Eindruck davon darlegen. Ironischer Weise muss ich trotzdem erstmal ne Inhaltsangabe machen. Das Paper ist auch garnicht schlecht.

Die Hausarbeit

Der Aufhänger ist die Dampfmaschine von James Watt. Um deren Output - ihre Drehgeschwindigkeit - unabhängig vom Kesseldruck konstant zu halten, baute James Watt einen Fliehkraftregler. Dieser macht, durch einen zentrifugalen Mechanismus, das Druckventil zu, wenn die Maschine schneller wird und wieder auf, wenn sie zu langsam ist. Ein Programm müsste das so erledigen: Erst wird die Geschwindigkeit gemessen, dann verglichen, ob sie zu schnell ist; dann wird errechnet, wie weit das Ventil geschlossen oder geöffnet werden muss, damit die gewünschte Sollgeschwindigkeit erreicht wird. Der Prozess muss natürlich in regelmäßigen Abständen wiederholt werden. Das Argument des Autors ist nun, dass der echte Fliehkraftregler nur schlecht durch den Algorithmus beschrieben wird. Hier sollte man eher mit Hilfe von Differentialgleichungen versuchen, den Mechanismus zu beschreiben. Beschäftigt man sich nun mit solchen dynamischen, gekoppelten Systemen, so erhält man bessere Modelle der Kognition, als wenn man immer nur so tut, als wäre ein Hirn auch gleich ein Computer.

Nach und nach hatte ich, durch viel Querlesen, verstanden, wo da die Probleme liegen. Zu allererst dachte ich, der Mann habe absolut recht und man bräuchte unbedingt die Theorie dynamischer Systeme zur Beschreibung von Kognition. Das Ganze liegt ja auch nahe: Kognition ist sicher ein "dynamischer Prozess" und vielen fällt es sicher schwer sich vorzustellen, dass im Kopf einfach ein Programm abläuft; aber so einfach ist die Diskussion hier nicht. Inhaltlich spannend, ich habe einige Papers zu dem Thema gelesen und am Ende hatte ich einen guten Überblick, dir, lieber Leser empfehle ich die Kurzübersicht (sorry, wissenschaftliche Paywall). Inhaltlich Spannend, aber nicht worauf ich hinaus will!

Haschd du gelernt?

Also: Komputation und Kognition. Das kann doch nicht so schwer sein. Als Informatiker kennt man sich ja mit Komputation aus, richtig? Naja, nicht ganz. Komputation muss halt auch erstmal definiert werden, bevor man sich drüber unterhalten kann. Und genau hier bringt der Autor den ersten Schnatzer: Er definiert einfach irgendwie zusammen. Dann vergleicht er das mit neuronalen Netzen und faselt dann was von dynamischen Systemen. Und der arme Student denkt nur: W. T. F. Aber das kommt vor, wenn man als Informatiker/Psychologe auf einmal philosophische Papers liest.

Zunächst war ich von den einzelnen Infos wie erschlagen. Die Autoren der Papers, allesamt Philosophen und Psychologen, gaben sich die Hand und hangelten sich von dynamischen Systemen zur Analyse von Flüssigkeiten, Neuronalen Netzen, Lern- und Motaivationstheorien über den Begriff von Repräsentation bis hin zur Nicht-Definition von Komputation. Es ging zu wie an einem Zirkustrapez. Keiner der Bereiche war mir wirklich intuitiv zugänglich, ich hatte immer das Gefühl, weit unter meiner Kompetenz zu arbeiten, hoffnungslos überfordert zu sein und aus dem Ganzen einfach nicht schlau zu werden. Nachdem ich dann mit Ach und Krach meine Hausarbeit beendet hatte (Rating in Progress), war ich irgendwie auch nicht schlauer. Mir war nur klar: Ich weiß, dass ich nichts weiß. Einfach zu kritisieren war, dass van Gelder hier und da einfach ein paar Definitionen weggelassen hatte und dynamische Systeme dann mit konnektionistischen Systemen (Natürliche Neuronale Netzwerke) in einen Topf warf. Darauf baute dann auch meine Hausarbeit auf - Ziel erfüllt würde ich sagen - aber viel mehr als die wahrheitsdehnende Herangehensweise von Herrn van Gelder wurden mir einige Punkte klar, die ich hier nun aufzeigen möchte.

1. Der Kaninchenbau

Die ganze Reise an die Grenzen meines Intellekts hat mir viel Spaß gemacht. Sie war höchst spannend und ultra bekloppt. Ich lernte die "Cognitive Science" als eigene Inter-Disziplin kennen, mir war nicht klar, dass dieser Begriff, den ich nun auch immer häufiger wahrnehme, ein eigenes Ding beschreibt. Ich dachte das sei eigentlich damit beendet, ein wenig Hirnanatomie und Psychologie zu diskutieren, aber dass es sich dabei um eine eigene Welt handelt, war mir nicht so klar. Die Psychologie hat noch viele Facetten und auch in der Informatik habe ich noch einige blinde Flecken - ich fühle mich wie Alice im Wunderland. Natürlich war das auch ein Benchmarking für meine eigene Ambiguitätstoleranz (toller Begriff, tolles Konzept).

2. Studium als Berufsvorbereitung? Sicher nicht!

Während ich mich mit den Inhalten beschäftigte, fiel mir auf, wie weit die Qualität und Informationsdichte in diesem Sektor der Wissenschaft sich von dem unterschied, was man sonst so im Studium hört. Das eine nenne ich mal die Bachelor-Seite, das ist die Perspektive, die man als Studienanfänger hat. Da wird in der Sozialpsychologie ein bisschen über irgendwelche verblüffenden Effekte gefaselt und man kommt aus dem Schmunzeln nicht raus, was für Pranks und Veräppfelungsaktionen heute teils als Wissenschaft durchgehen, andererseits lernt man ein bisschen Statistik und komische Fakten über Reliabilitäts-Skalen in der Diagnostik, liest hier ein Paper, da ein Paper, alles nichts Weltbewegendes... Aber dann macht man einen Schritt ins falsche Seminar und versteht nur Bahnhof. Da kommt höhrere Mathe zum Einsatz und die Leute beschreiben Probleme mit Analogien, die man nicht mal im Ansatz versteht. Die Autoren bedienen sich Theorien aus zig verschiedenen Disziplinen und springen von Informatik, Neurologie, Motivation zu Mathe und wieder zurück, ziehen dabei nicht über Los und sammeln auch keine 4000 Euro auf dem Weg... Das ist einerseits wunderschön: Es gibt so viel zu entdecken und immerhin habe ich diesen Kaninchenbau ja auch im Rahmen meines Studiums kennengelernt, aber es war dann doch leider eher vom Zufall getrieben. Ich kannte den Veranstalter, der kannte mich, ich hatte halt n bisschen Informatik gemacht und mit ihm diskutiert. Zwischen Tür und Angel dann fiel ihm ein, dass ich ja in das Seminar passen würde, zusammen mit den Leuten vom IWR gabs dann gute Diskussionen. Das Alles würde ich aber eher als Zusatzveranstaltung deklarieren. Aus dem regulären Bachelorstudium heraus wurde mir nicht mal klar, dass es diesen Kaninchenbau gibt. Eine Kritik des Bachelors ist aber grad so ausgelutscht wie Sänkyoufortravelingwisdeutschebahn, daher beende ich den Punkt an dieser Stelle.

3. Studier auf keinen Fall Psychologie!

Wenn man an Psychologie denkt, dann denken viele sicher erstmal an die Psychotherapie, also den klinischen Bereich (deswegen denken viele wohl auch, ich wollte umsatteln und kein Informatiker mehr sein, was aber Quatsch ist). Viele meiner Kommilitoninnen sind tatsächlich eher am Institut, weil sie Therapeutinnen werden wollen - mit Menschen arbeiten, ihnen helfen, empathisch sein. Klinischer Bereich eben. Da sind solche Inhalte, wie ich sie bisher erlebt habe aber doch eher hinderlich; eigentlich sollte das Studium ja auf einen Beruf vorbereiten, aber, sein wir nicht naiv, das tut es nur selten. Das Studium ist sicher geeignet als eine Vorbereitung auf eine wissenschaftliche Karriere, wenn man aber Thearapeut werden möchte, muss man ohnehin nach dem Studium erstmal eine Ausbildung machen. Die ganze Statistik und das wissenschaftliche Arbeiten kann man sich dann auch sparen, wenn man eine Praxis hat (ich kenne viele Therapeuten, ratet mal, wie viele von denen jeden Tag eine Varianzanalyse rechnen).

Aber klar, so einfach ist es nicht und ich will auch nicht abstreiten, wie sinnvoll eine Ausbildung auf wissenschaftlicher Basis ist. Allerdings fehlt mir hier etwas die Mitte zwischen Theorie und Praxis. Ich kenne studierte (Uni-) Informatiker, auch Unformatiker genannt, die könnten nicht programmieren, um ihre eigene Mutter zu retten - ich kenne aber auch praktizierende Programmierer, die seit 10 Jahren Java machen und nen Bogosort nicht von nem Shellsort unterscheiden können. Ich möchte sagen: Theorie und Praxis: Ja beides - aber wenn man absehen kann, worauf man hinaus will, dann sollte man die Möglichkeit haben, den Overhead zu reduzieren.

4. Mehr Respekt vor Philosophen!

Gemeiner Witz: Was sagt ein arbeitsloser Philosoph zum arbeitenden Philosophen? Einmal zum Hauptbahnhof bitte!

Das Cliché lässt sich nur schwer wegbekommen und einige Studenten der Philosophie sind kaum in der Lage, auch nur einen klaren Gedanken zu fassen und zu formulieren. Besonders in der Aufarbeitung des Papers war ich aber erstaunt, wie gewinnbringend da diskutiert wurde und wie klar die Konzepte an vielen Stellen waren. Ich hatte an einigen Stellen einfach keine Ahnung, wovon da gesprochen wird, aber das lag zumeist nicht an den Ausführungen selbst, sondern daran, dass ich halt mit dem Thema keine Erfahrungen hatte. Ist ja auch nicht schlimm, wenn man dumm ist, ist nur schlimm, wenn man dumm bleibt.

Die Leitfrage war ja sehr spannend: Ist die Kognition eher ein Computer oder ein dynamisches System? Die Beantwortung der Frage beinhaltete dann auch neuronale Korrelate, also einen Blick auf die Hardware. Wieder andere versuchten eine Verbindung zwischen Individuen und dem Sozialen Netzwerk eines Gehirns herzustellen. Alle diese Phänomene haben eines gemeinsam: Sie entziehen sich der direkten Messung. Daher war die Analyse des Sachverhalts eher auf einer sehr theoretischen und eben auch philosophischen Ebene. Und genau da wurde es interessant, denn die Philosophie stand nicht nur als bedeutungslos-"künstisches" Abstraktum im Raum, sondern wurde direkt aus konkreten Kenntnissen abgeleitet.

Ich komme daher zu dem Schluss: Philosophie ist extrem geil und total wichtig. Gute Philosophie ist praxisnah und nicht einfach nur was für Taxifahrer. Ich würde sogar noch weiter gehen. Wer es sich leisten kann, sollte sich einen Philosophen angeln und in die Firma holen. Philosophen bringen durchweg interessante Skills mit, die auch in der IT Verwendung finden könnten. Sie sind gut im Zerdenken und analysieren, die können sich mit abstrakten Dingen beschäftigen, und und und. Das alles sind Skills, die ein Informatiker oder Softwareentwickler idealer Weise auch mitbringt.

5. Oma Code

Bei meinen Recherchen fühlte ich mich oft an das folgende Zitat erinnert, welches Albert Einstein zugeschrieben wird:

If you can't explain it simply, you don't understand it well enough.

Viele Autoren kleideten sich in komplizierte Ausdrücke und machten sich keine Mühe, genaue Definitionen anzulegen. Das ist auch das, was meiner Kritik von schlechtem Code zu Grunde liegt - sich einfach auszudrücken ist extrem schwierig, besonders, wenn man komplizierte Gedanken hat. Wenn man abstrakte Systeme beschreibt und diese dann in Code konkretisiert, so erhält man ein Abbild des Systems - wenn das im Code aber komplizierter ist, als es in Wirklichkeit sein muss (das ist das, was wir sowohl als Over-Engineering als auch als Spaghetti-Code bezeichnen), dann ist das oft auch ein Zeichen dafür, dass an verschiedenen Stellen Unsicherheit besteht.

Das Zitat liefert eine gute Heuristik (Daumenregel): Wenn der Code kompliziert ist, ist das Problem unklar. Das ist übrigens garnichts neues. Auf Ernest Rutherford geht folgender Spruch zurück:

A good scientific theory should be explicable to a barmaid.

In der Beziehung auf Quellcode nenne ich persönlich das Prinzip den "Oma-Code". Der Code sollte dem Sekretär oder der eigenen Oma erklärbar sein (oder jemandem ohne technischen Hintergrund). Wenn man sich im agilen Umfeld umsieht, gibt es auch einige Instrumente, die dabei helfen sollen, die Komplexität der Gedanken oder zumindest des Ausdrucks zu reduzieren, wie beispielsweise User Stories oder die Ubiquitous Language im Domain Driven Design.

6. Don't bullshit a bullshitter

Auf Walter White aus der genialen Serie Breaking Bad geht dieser Satz zurück. Wer immer nur kompliziert daherredet, verhindert, dass man irgendwann die wirklich komplexen Probleme von den einfachen Problemen unterscheiden kann.

Als Programmierer sind wir Fans unserer Fachsprache. Wir freuen uns über die komplexen Algorithmen und komischen Muster, die seltsamen Begriffe, die keiner sonst versteht. Du, lieber Leser merkst das vielleicht, wenn du im Freundeskreis mal mit Nicht-Informatikern weggehst (oder Nicht-Psychologen), als Informatiker unter Psychologen merke ich das jeden Tag. Je nach dem wie gut man sich in einem Bereich auskennt, merkt man auch, wenn jemand Unfug redet. Beim Schreiben der Hausarbeit dachte ich oft, ich sei zu doof, um einige Sachverhalte zu verstehen und das mag auch an vielen Stellen so gewesen sein, allerdings gab es auch Momente, wo ich entgeistert ins Leere blickte, als mir klar wurde, dass da gerade einer Unfug erzählt.

Zenit meiner Recherche war folgende wunderbare Begegnung mit den Ausführungen von Barbara Fredrickson. In ihrem Paper "Positive Affect and the Complex Dynamics of Human Flourishing" (American Psychologist, 2005, 60,7, pp. 678-686) beschreibt sie, zusammen mit Marcial Losada, die "Positive Affect Ratio":

The authors predict that a ratio of positive to negative affect at or above 2.9 will characterize individuals in flourishing mental health.

Bisher war ich überzeugt, dass die Theorie dynamischer Systeme angemessen sei, um bestimmte Aspekte zu beschreiben. Beim Lesen dieses Papers kamen dann doch Zweifel auf. Da wurden beispielsweise mit dem Lorenz-Attraktor argumentiert, Details weggelassen und Methodisch einfach irgendwelche Annahmen getroffen, die dann als selbstverständlich dargestellt werden. Als unbedarfter Student hat man natürlich erstmal das Vertrauen, dass das alles mit rechten Dingen zugeht. Immerhin wusste vor dem Lesen nicht mal, was genau der Lorenz-Attraktor ist. Hatte ich mal gehört, mehr aber auch nicht. Doch wie genugtuend ist es, dann eine antwortende Streitschrift in einem anderen Paper zu lesen. Allein der Titel ist zum totlachen:

The Complex Dynamics of Wishful Thinking: The Critical Positivity Ratio

(Brown, N. J.L., Sokal A. D., & Friedman, H. L., 2013, American Psychologist, 68). Die Autoren nehmen die Ausführungen des, tatsächlich sehr oft zitierten, Papers von Fredrickson und Losada auseinander. Sie beschreiben methodische Fehler und interessante Auslegungen. Sie enden in der folgenden Money Quote:

Let us stress that our concern here is with the objective properties of published texts, not the subjective states of mind of the authors (which might, however, be of interest to philosophers, such as Frankfurt, 2005)

Aha, was hat denn Frankfurter zu dem Thema beizutragen, fragt sich der interessierte Student. Ein genaueres Studium des Quellenverzeichnis liefert dazu folgende Referenz:

Frankfurt, H. G. (2005). On bullshit. Princeton, NJ: Princeton University Press.

Ich bin fast vom Stuhl gekippt vor Lachen. Und damit wird wohl klar, was einige Schlechtcodeschreiber und Verwirrungswissenschaftler so treiben:

If you can't convince them - confuse them. - Harry Truman

Readability Studie - Antwortdaten

Zur Vorbereitung meiner Bachelorarbeit bereite ich zur Zeit die Daten meiner Studie auf. Im Rahmen der Studie sahen Teilnehmer einige Fragebögen. Die Antwortdaten dieser Fragebögen habe ich nun etwas aufbereitet und sie sind hier verfügbar:

Antwortdaten als Google Spreadsheet

Ich habe peinlichst darauf geachtet, dass keine Daten veröffentlicht werden, die Individuen identifizierbar machen. Sollte ich da was übersehen haben sagt mir bitte umgehend Bescheid!

Clean Code - Das Fehlende Kapitel

Heute habe ich was schönes für euch. Vor einer Weile hatte ich einen Artikel über Weasel Words geschrieben. Weasel Words - zu Deutsch etwa "Worthülsen" sind Begriffe, die wir Entwickler gerne in unseren Code einbauen, die aber keine wirkliche Bedeutung haben. Das merkt man daran, dass der Code nicht schlimmer - eher sogar besser - wird, wenn man sie einfach weglässt.

Muss es ein DatabaseConnectionManager sein oder reicht eine Connection - weil ich mich eh im Namespace "Database" befinde? Brauche ich ein CustomerServiceMessageRepository, oder kann die Klasse auch Messages heißen?

"Weasel Words" sind ein wichtiger Baustein in Gesamtkonzept von "Empathic Code". Inspiriert wurde die Idee von James Martin, der den Begriff in diesem Kontext geprägt hatte, als ich in London bei Riverglide arbeitete.

Der Artikel ist nun online verfügbar, mit freundlicher Genehmigung von Tilman Börner, dem Chefredakteur der dotnetpro. Wenn euch der Artikel gefallen hat, kann ich nur ein Abo der Zeitschrift empfehlen. Sie beinhaltet aktuelle Themen und interessante Ideen zum Thema Softwareentwicklung. Mittlerweile taucht auch immer mehr JavaScript auf, daher denke ich, dass auch für nicht C#-Entwickler auf jeden Fall etwas dabei ist. Als Geheimtipp sei übrigens gesagt, dass Abonnenten Zugriff auf alle bisher geschriebenen dotnetpro-Artikel haben. Das waren im März 2013 immerhin 3034 Artikel von Autoren wie Golo Roden und vielen weiteren inspirierenden und kompetenten Persönlichkeiten.

Download: Clean Code - Das Fehlende Kapitel

Readability Studie - Gedanken zu meinem Poster

Im Rahmen meiner Empra Studie habe ich für den Posterkongress zum Ende des Semesters ein Poster gestaltet, auf dem die Ergebnisse meiner Arbeit zusammengefasst präsentiert werden. Die Poster des Kongresses wurden von verschiedenen Fakultätsmitgliedern bewertet und ich gewann den dritten Platz. Das freut mich natürlich sehr. Hauptziel meines Posters war allerdings nicht, irgendwelche Preise abzustauben, sondern erst einmal ansprechend zu wirken. Damit wollte ich bewusst ein Statement setzen, da ich viele wissenschaftliche Poster als sehr konservativ - um nicht zu sagen langweilig - wahrnehme.

Würdigung und Kritik

Meine Kommilitonen haben alle so wunderbare Arbeit und damit einen wichtigen Beitrag zur Wissenschaft geleistet. Daher finde ich es schade, dass diese ausgezeichneten Arbeiten später so unästhetisch präsentiert wurden. Ich möchte nicht behaupten, dass sie sich keine Mühe mit den Poster gegeben haben. Im Gegenteil, alle haben unsagbar viel Mühe investiert. Allerdings umfasst das Problem viele Poster auch außerhalb meines Jahrgangs. Nicht jeder Wissenschaftler hatte eben Kunst im Abitur belegt und sich mit Typographie beschäftigt. Ich möchte hinterfragen, ob sich die Wissenschaft damit einen Gefallen tut. Eine angenehme, angemessene und emotionale Aufbereitung der Ergebnisse könnte Anderen ebendiese einfacher zugänglich machen und sogar Laien dazu bringen, sich mehr mit ihnen zu beschäftigen und Interessierten die Angst vor komplexen Sachverhalten - gar der Statistik - nehmen. Ich will aufzeigen, dass sich diese beiden Pole nicht ausschließen. Form und Funktion sollten geeinigt und nicht gegeneinander ausgetauscht werden. Nicht zuletzt der Erfolg der Produkte der Firma Apple zeigen, dass es sich lohnt, sich mit diesem Prinzip zu beschäftigen.

Appell

Dies ist meine subjektive Wahrnehmung der Poster und die ist natürlich extrem beschränkt (und 'biased'), aber ich meine, dass das Poster als Medium schnell und informativ sein sollte. Deswegen muss es zunächst eine emotionale Nachricht senden, die den Betrachter einfängt und bindet und Lust auf mehr macht. Ich schreibe übrigens bewusst "Betrachter" - denn ein Poster sollte nicht für "Leser" sein. Leser sollten das dazugehörige Paper lesen - dort werden Details geklärt. Das Poster kommuniziert anders. Ich denke, dass beispielsweise die Werbeindustrie diese Meinung teilt. Wann haben Sie das letzte Mal einen langen Fließtext auf einer Plakatwand gesehen?

Ich hoffe dass ich mit meiner Arbeit meinen Kommilitonen eine Inspiration sein konnte. Deren positives Feedback zu meinem Poster beflügelte mich sehr. Danke, ich freue mich, dass euch das Poster gefallen hat.

Und nun zum eigentlichen Poster.

Readability Studie - Entwicklertagebuch

Sehnsüchtig warten die Teilnehmer meiner Studie schon auf deren Ergebnisse - bisher hatte ich es noch nicht geschafft, diese vorzustellen - zumindest bei denen, denen ich ebendies versprochen hatte. Die Studie fand im Rahmen meines empirischen Praktikums - kurz: EMPRA - statt. Es handelt sich dabei also noch NICHT, wie von vielen fälschlicher Weise angenommen, um meine Bachelorarbeit, allerdings dient die Studie der Vorbereitung ebendieser.

Für die hohe Latenz entschuldige ich mich aufrichtig und möchte mich herzlich bei den Teilnehmern bedanken - ohne euch hätte ich es nicht schafft! Danke, liebe Teilnehmer, dass ihr mir geholfen habt

Ich habe viel durch die Studie gelernt und daher einiges zu erzählen. Inhaltlich ist erst mal spannend zu berichten, worum es ging und was da gemacht wurde - die Kurzversion. Den einen oder anderen mag aber vielleicht auch das Making-Off und die Theorie interessieren. Aktuell liegen nur die "Uni"-Ergebnisse vor. Der Bericht beinhaltet beispielsweise Details zu den verwendeten statistischen Methoden, allerdings ist mir klar, dass diese nicht für jeden unmittelbar interpretierbar sind. Daher werde ich, so schnell ich kann, eine Version der Ergebnisse schreiben, die auch Nichtwissenschaftler verstehen.

Ergebnisse

In einem Satz

Durch explizite Bezeichner (customer, request, repository, etc.) lassen sich, gegenüber Abkürzungen (acm, req, rep, etc.) und einzelnen Buchstaben (a,c,s, etc.) Fehler in Quellcode um zwischen 10 und 25% schneller (und präziser) finden.

Details

Die Ergebnisse der Studie lassen sich am Besten durch mein Poster erfassen. Das Poster wurde, nach dem die Studie durchgeführt worden war, im Rahmen des Praktikumskongresses erstellt. Genaueres kann dem Studienbericht (Pdf) entnommen werden. Dieser beinhaltet eine konkretere Herleitung und eine genauere Diskussion meiner Theorien, sowie - wahrscheinlich - viele, viele Rechtschreibfehler.

Interessant ist vielleicht noch eine kleine Beschreibung des Prozesses. Immerhin ist es meine erste Studie gewesen und hoffentlich nicht meine letzte.

Hintergründe

Ich habe die Software zur Erhebung selbst entwickelt und möchte bald ihren Source Code veröffentlichen. Leider ist sie in einem - für meinen Geschmack -furchtbaren Zustand. Sie kommt mit wenig aus, aber beinhaltet viele Quirks und Eigenarten, die vielleicht nicht ganz nachvollziehbar sind.

Umsetzung

Als Server verwendete ich Flask, den ich auf Heroku hostete. Die Datenanbindung wurde über MongoHQ bewerkstelligt. Die Hauptarbeit steckte im Client. Diesen baute ich mit Twitter Bootstrap und viel händischem JavaScript. Ich evaluierte mehrere Frameworks und entschied mich dann für eine Eigenentwicklung für den Client. Die Fragebögen tippte ich in plain HTML.

Positiv: NoSql

Angenehm war dabei, dass die HTML Forms in Flask einfach als Python-Dictionaries ankamen, die ich 1:1 an MongoHQ als Json/BSON Dokumente weiterreichen konnte. Dadurch bestimmte die HTML Seite, welche Daten ich erhalten möchte - an einer einzigen, zentralen Stelle. So angenehm lässt es sich mit keinem OR/M arbeiten und ich glaube, dass NoSQL für den Einsatz höchst angemessen, aber mindestens ausreichend war.

Positiv: Bootstrap

Ich war sehr "geflashed" von Bootstrap. Es hat mir unendlich viel Arbeit leichter gemacht. Zuvor hatte ich nicht verstanden, dass BS auch viel JavaScript magic mitbringt. So entdeckte ich bei der Entwicklung, dass durch einbinden der mitgelieferten .js Datei bestimmte Funktionen verfügbar wurden, die ich durch ´´´data-´´´ Attribute bestimmter HTML(5)-Tags aktivieren konnte. Ein Segen.

Fehlentscheidungen

Blöd war eigentlich nur das HTML für die Fragebögen. Ich hatte angefangen, eine Fragebogen-DSL zu schreiben. Leider kam der Parser nicht zum Einsatz, weil ich bei seiner Entwicklung das Gefühl hatte zu prokrastinieren und mich zwang, mich mehr auf die eigentlichen Daten zu konzentrieren, anstatt mal wieder ein Datenerfassungsframework zu bauen. Ich handelte damit - gezwungener Maßen - gegen das Motto von Terence Parr (der Typ der Antlr gebaut hat):

"Why program by hand in five days what you can spend five years of your life automating?"

Persönlich

2011 kam ich an die Uni Heidelberg und begann dort mein Psychologiestudium. Dieses war zunächst inhaltlich sehr allgemein gehalten, jedoch hatte ich das Bedürfnis, konkrete Fragestellungen zu beantworten. Das Empra war der Raum für eigene Ideen und somit die erste Chance, eine Studie zu einem von mir definierten Thema zu machen. Leider kam es da zu dem "Drei Stooges Syndrom" - die Blockade die entsteht, wenn alles auf einmal raus muss.

Three Stooges

Auch als K59.0 im ICD-10 zu finden. (src

Daher dauerte die Studie länger als geplant und dadurch entstanden auch die langen Pausen zwischen der Registrierung, der eigentlichen Studie und der Auswertung. Aber nun sind die Wogen geglättet und erste Ergebnisse liegen vor.

Diskussion

Viele Daten wurden ausgewertet, aber einige Daten wurden aus Zeitgründen einfach ignoriert. Das Semesterende nahte und die Studie musste beendet werden, deswegen finden sich nicht alle gewonnenen Kenntnisse im Studienbericht dokumentiert. Allein das bereits Erhobene ist ausreichend, um eine kleine Bachelorarbeit zu füllen und verschiedene Folgestudien sind bereits in Sicht.

Und für die brauche ich sicher bald wieder Teilnehmer :)

Developer Open Space 2013

Der Developer Open Space 2013 in Leipzig ist beendet! Vom 18. - 20. Oktober hatten viele bekannte und neue Gesichter hier ein Stelldichein und es kamen ausgezeichnete Gespräche zustande. Ich habe so viele neue Inspirationen erhalten und konnte wohl auch das Eine oder Andere einbringen. Von einigen Eindrücken möchte ich hier berichten.

Übersicht

  1. Meine Studie
  2. Werte
  3. SignalR
  4. Motivation - Drive
  5. Empathic Presentations
  6. Sessions
  7. Abschluss

Meine Studie

Zu allererst fühlte ich mich verpflichtet, etwas über meine Studie zu erzählen. Diese hatte ich mittlerweile beendet und viele Teilnehmer des Open Space wahren wohl auch Teilnehmer meiner Studie gewesen. Da die Teilnahme nicht entlohnt (bezahlt) wurde, hatte ich versprochen, möglichst schnell über die Ergebnisse zu berichten. Dies bewerkstelligte ich in einer eigenen Session - aber dazu habe ich einen eigenen Bericht geschrieben.

Werte

Zuerst möchte ich den größten Brocken dokumentieren. Ich hatte mehrere Aha-Erlebnisse in Leipzig, eines davon war - überspitzt formuliert - was Sexismus mit agiler Softwareentwicklung zu tun hat. Ich hatte vor längerem zum Thema Genderforschung eine Vorlesung gehört. In dieser lernte ich, dass Stereotypen eigentlich der kognitiven Haushaltung dienen. Stereotypen selbst sind erst mal sinnvoll und notwendig und lediglich bildhafte Klassen von Konzepten. Beispielsweise hat wohl jeder ein Bild im Kopf, wenn ich von einem "Stuhl" spreche. Wenn man nun einen stereotypischen Stuhl beschreiben würde, dann ist das Ergebnis vielleicht: Ein Stuhl hat vier Beine und eine Sitzfläche, sowie eine Lehne. Das ist ein Stereotyp, der schonmal gar nicht so richtig ist, da die wenigsten Programmierer bei der Arbeit auf solchen Stühlen sitzen. Wahrscheinlicher ist es, dass sie auf einem schwarzen, höhenverstellbaren, gepolsterten Drehstuhl mit Armlehnen sitzen. Der Stereotyp kann eben täuschen. Das ist erst mal auch nicht so schlimm - schlimm wird es erst, wenn man aufgrund des Stereotypen anfängt, zu diskriminieren und aufgrund von Stereotypenzugehörigkeit (oder eben deren Abwesenheit) Hass zu schüren. Der Stereotyp selbst ist erst mal ok, denn er ist lediglich eine Art Datenreduktion um vereinfacht denken zu können.

Die Sexismusdebatte beinhaltet unter anderem eine Diskussion von Geschlechtsstereotypen. Diese beinhalten deskriptive (Männer / Frauen sind so) und präskriptive (Männer / Frauen sollen so sein) Elemente. Leider wird in der Diskussion immer viel gemischt, sodass man zwischen dem biologischen Geschlecht (Sex) und dem sozialen Geschlecht (Gender) trennen sollte. Unabhängig von der eigentlichen Biologie lässt sich beschreiben, dass Männer männlich und Frauen weiblich sind - aber was bedeutet das? Durch den weiblichen Stereotypen wird Frauen zugeschrieben, dass sie empathisch und harmonieschaffend sind; stereotypische Männer hingegen sind eher selbstbehauptende Problemlöser. Es gibt aber auch Männer, die eher harmonieschaffend und empathisch sind und auch Frauen, die mal auf den Tisch hauen können - daher sollte man nicht zwangsweise über Mann und Frau (das biologische Geschlecht) reden, sondern über die Werteklassen "agentisch" und "kommunal".

Agency - Agentisch ist das "sich behauptende" - "stereotypisch männliche". Diese Werte finden sich auch in der Geschäftswelt. Eher konservative Großfirmen, stereotypisch und reduktiv als "Enterprise" gelabelt, sind eben eher "männlich" agentisch. Es geht ihnen ums Geldverdienen, Probleme lösen, Produktivität steigern, Leisten und Kontrollieren und Wachstum. Wenn agile Entwickler und Coaches nun ankommen, dann reden sie oft über selbstorganisierende, harmonierende Teams, Kommunikation, Verständnis des Kunden, Menschen vor Prozessen. Ein Teil des Manifesto ist beispielsweise

"[Wir wertschätzen...] Kollaboration gegenüber Vertragsverhandlungen".

Ziel ist es also, im Rahmen agiler Methoden, durch Kollaboration Vertrauen aufzubauen, anstatt durch Verträge auszuhandeln, wie jemand bestraft wird, wenn er ein Ziel nicht erreicht. Und diese Schaffung von Harmonie ist eher ein Teil des weiblichen Stereotyps. Man könnte überspitzt also sagen, dass "Agile" bedeutet, weibliche Werte in eine männliche Welt zu bringen. Aber solche Wertunterschiede beherbergen viele Konflikte.

Die Parallele mag vielleicht dem einen oder anderen etwas weit hergeholt erscheinen, aber ich glaube, dass eine weitere Diskussion hier neue Lösungsansätze für viele Probleme bringen könnte. Ich höre nun jedes Mal, wenn jemand schreit: "Wir wollen mehr Frauen in der IT" stattdessen eher "Uns fehlen kommunale Werte in der IT". Und Empathic Code ist eben meine Art, genau diese Werte in der Programmierung zu etablieren.

Aber nun zu mehr technischen Aspekten. Immerhin war es ein Open Space für Entwickler.

SignalR

SignalR ist ein Framework, das bidirektionale, stehende Verbindungen zwischen einem (Browser-)Client und einem .NET-basierten Server aufbauen kann. Es ist quasi die C# Version von Socket.IO und bietet neben WebSockets auch weitere Fallbacks (json polling, etc.). Als lustige Machbarkeitsstudie gibt es übrigens Gif-Sockets. Man lädt so lange Frames in einem Gif und terminiert es nicht - zack hat man einen laufenden Datenstrom - die WebSockets der 90er. Geht in ie6.

Lange dachte ich darüber nach, was man damit machen könnte (WebSockets, nicht gif-Sockets ;), aber mir fiel ausser einem Twitter-Klon oder einem X-beliebigen Admindashboard nichts ein. Dann wurde mir klar, dass daran ja toll ist, dass - durch die stehende Verbindung - der Server auch Nachrichten an den Client schicken kann.

Wie Schuppen fiel es mir von den Augen, wie genau das eines meiner Probleme löst. Ich fühlte mich wie Sudden Clarity Clarence . Udo Wiegärtner fing den Moment mit meiner Kamera ein!

Sudden Clarity Cessor

Die Software soll nach und nach alle PDFs für die Vorlesungen der Studenten herunterladen und neue Dateien anzeigen. Zwar sind die verfügbaren UI-Libraries in Python alle nahezu plattformunabhängig, aber die Apis gefallen mir nicht (ich finde sie hässlich) und teils liegen ihnen seltsame Paradigmen zugrunde, die mir die Arbeit erschweren.

Meine Lösung: Statt einer nativen Windows/X/Gnome/Linux/MacOs GUI einfach eine Browserseite öffnen. In die kann ein Server dann einfach UI-Updates per WebSockets "streamen". Wenn sich also wirklich was ändert, kann der Server das an die UI "pushen", anstatt auf ein zyklisches Polling zu warten. Das ermöglicht auch, generische UIs für Technologien zu schreiben, die eigentlich nicht für den lokalen Programmbetrieb gedacht sind.

Es ließen sich auf diese Weise plattformunabhängige GUIS schreiben - im Browser eben. Ein moderner Browser sollte immer verfügbar sein und so könnte man eine Gui-Api für Node oder Ruby schreiben, die einfach Ausgaben an den Browser schickt. Damit kann ich nun eine Gui bauen, die nicht auf dieses saudämliche TKinter angewiesen ist und sich durch HTML5, CSS und JavaScript, Bootstrap und Co. schön, responsiv, plattformunabhängig und nicht-verwirrend. Einzige Voraussetzung ist eine WebSocket-Implementierung für den Server und ein moderner Browser. Tatsächlich sieht selbst zwischen IE, Chrome und Firefox das Look-And-Feel eine mit Bootstrap gebaute Website gleicher aus als das L-A-F zwischen TKinter auf Windows und Linux.

Wahrscheinlich ist die Idee nicht neu und schon tausende Leute hatten sie vor mir - mir wurde das Prinzip aber erst am Open Space klar und ich habe mich gefreut.

Das Ergebnis unserer Session auf dem Open Space findet ihr übrigens hier: SignalR Beispiel

Motivation - Drive

Oft kommt an so einem Open Space der Spruch "Wechsel doch den Job, wenn's dir nicht passt". Besonders wenn es um nicht-agile Chefs, Firmen oder Teammitglieder geht. Klar, aber das geht nicht so einfach. Jedoch sollte jeder diese Frage beantworten: Was hält einen in der Firma? Warum kommen die Kollegen zur Arbeit? Warum opfern mache dem allmächtigen C#-Gott ihre schönste Ziege und andere machen nur 925 (Nine to Five)? Was bewegt uns, was treibt uns an, was motiviert uns? Ich finde am nächsten Open Space sollten wir genau das diskutieren. Bis dahin empfehle ich das Buch "Drive" von Daniel Pink- es bietet eine tolle Diskussionsgrundlage.

Empathic Presentations

Wie präsentiere ich angemessen, ansprechend, informativ und nicht langweilig? Zu Ende der Sitzungen am Open Space diskutierten wir (etwas unter Zeitdruck), was eine gute Präsentation ausmacht. Anregung möchte ich durch meine Folien und Vorträge geben, aber ich denke dass dieses Thema noch einmal ausführlich besprochen werden sollte.

Bedanken möchte ich mich bei den Teilnehmern der Session, die so viel Gutes beizusteuern hatten! - zuletzt Marco Rasp, der auf dieses Video hinwies.

Sessions

Ich empfand leider oft as unangenehm, dass auf dem Open Space noch sehr viel in "Tracks und Sessions" gedacht wurde. Eigentlich soll der Open Space ja eine "Unkonferenz" sein. Ich fand, dass sehr oft durch Zeitdruck Teilnehmer einfach "abhauten" oder nicht zu Ende gehört wurden. In der weiter oben genannten "Werte" Session entschied die Gruppe jedoch zu bleiben - zum Unwohlsein derer, die forderten dass irgendein anderes Thema (Elixir?) diskutiert werden müsse. Prinzipiell hat es also geklappt, aber der Raum für Diskussion musste umkämpft werden. Und warum braucht man immer nen Raum? Das Wetter war doch toll? Hier wünsche ich mir ein wenig mehr Dynamik.

Abschluss

Trotz aller Kritik möchte ich zum Schluss noch ausdrücken, wie ausgesprochen bereichernd der Open Space für mich war. Persönlich möchte ich teilen, dass ich sehr glücklich bin, am OS teilnehmen zu dürfen und so Feedback zu erhalten, um mich selbst zu reflektieren und mich intellektuell auszutauschen, wunderbaren Menschen emotional und fachlich zu begegnen, die mich in einem Ausmaß bereichern, das weit über die Möglichkeiten einer Universität hinausgeht.

Bedanken möchte ich mich bei

Alexander Groß, Alexander Zeitler, Andreas Richter, Benjamin Bock, Christian Fiebrig, Christoph Stock, Gregor Woiwode, Hans-Peter Schelian, Hendrik Lösch, Ilker Chetinkaya, Jan Fellien, Krisztina Hirth, Lars Kumbier, Marcel Hoyer, Marcell Spies, Marco Rasp, Mario Binder, Marius Schulz, Mariusz Kogut, Max Malook, Mike Bild, Oliver Guhr, Robert Mühsing, Sascha Dittmann, Sebastian Seidel, Sebastian Mansow-Model, Stefan Cullmann, Stefan Reissmann, Sven Sönnichsen, Thomas Bandt, Thorsten Dörfler, Timur Zanagar, Torsten Weber, Udo Wiegärtner, Uli Armbruster und vor allem Tala Otte und besonders Jochen Schaffer und Niels Hebling und allen die ich gerade in der Liste vergessen habe oder deren Twitter Namen ich nicht auswendig kenne, oder die keinen haben, aber die den OS so toll gemacht haben.

Weitere Links:

Bilder, Uli Armbrusters Blog mit mehreren Artikeln zum Devspace

Kommt in die Devspace Teilnehmer Gruppe auf Trello! Fragt mich am Besten auf Twitter und ich füge euch hinzu. Auch ohne Mitgliedschaft lohnt sich sicher die Buchliste oder das Board zu UI-UX, zu dem jeder etwas beitragen darf!

Vortrag: Empathic Refactoring

An der Developer Week 2013 hielt ich einen Vortrag über Empathic Refactoring. Anhand des Refactorings Replace Conditional with Polymorphism versuche ich zu beschreiben, wie sich Refactorings nicht nur durch striktes Befolgen von Entwurfsmustern, sondern eher durch das intuitive Bauchgefühl ergeben.

Wie gut mir das gelungen ist, müsst ihr selbst entscheiden. Schöner und beeindruckender ist das natürlich, wenn man echten Code refaktorisiert (euren eigenen :) ).

Hier findet ihr die Vortragsfolien.

Während des Vortrags verweise ich u.a. auf Prof. Dr. Funke.Dieser ist der Direktor des Psychologischen Instituts der Universität Heidelberg und führt ein illusteres Blog. Dort findet man auch Informationen zur besagten Tailorshop App: Tailorshop: Ein wiederentdecktes komplexes Problem

Die (verhältnismäßig unspektakuläre) App könnt ihr euch unter folgenden Link ansehen. Beachtet: Es handelt sich dabei nicht unbedingt um eine klassische fancy-pants Webapp, sondern um ein Erhebungsinstrument, das teils etwas andere Anforderungen mitbringt. Die Architektur kann sich jedoch insgesamt sehen lassen. Zur Anwendung kamen knockout.js, jQuery, nodejs und express. Sie ist lokalisierbar und durch eine kleine DSL sehr gut konfigurierbar. Dadurch ist sie sehr angenehm zu warten. Der Sourcecode wird bald veröffentlicht, vielleicht lassen sich anhand der Software ein paar Refaktorisierungen diskutieren? http://tailorshop.herokuapp.com/demo/

Ich bedanke mich weiterhin bei der Organisation der Developer Week, bei der Neue Mediengesellschaft Ulm mbH und bei Developer Media für das Video.

Readability Studie - Anmeldung

Im Rahmen meines Psychologiestudiums entwerfe ich zur Zeit eine Studie. Ich habe eine Theorie entwickelt, wie Code gelesen und verstanden wird. Diese möchte ich gerne empririsch überprüfen. Und brauche dazu noch Versuchsteilnehmer.

Auf http://weaselhunter.com könnt ihr euch für meine Studie eintragen.

Was euch erwartet

Wenn ihr teilnehmt bekommt ihr ca. 30 Minuten lang C# Snippets gezeigt. Diese wurden auf eine bestimmte Art und Weise designt. Darin müsst ihr Fehler finden und dann noch einige Fragen beantworten.

Was ihr davon habt

Ich lasse euch selbstverständlich an den Ergebnissen teilhaben! Nach Absprache präsentiere ich die Ergebnisse persönlich in eurer Firma!

Frage: Ich hab mich eingetragen...

...und nun?

Antwort: Bitte noch etwas Geduld...

Danke an alle, die sich bereits eingetragen haben. Viele haben mich auf dem Open Space in Karlsruhe gefragt ob "da noch was kommt...". Klar, aber ich bitte euch um etwas Geduld, denn ich bin noch nicht so weit.

Ich will ehrlich sein: Die Studie ist für mich ein Dauerbrenner und ich schraube und feile daran schon ein ganzes Weilchen rum. Es soll eben richtig, richtig gut werden. Ich lese wissenschaftliche Papers zu den Themen Psycholinguistik, Programmierung und Kognition und lese mich in die Versuchsplanung ein.

Zur Zeit tweake ich den Client, den ich für die Erhebung verwenden werde. Diesen werde ich euch als Link bereitstellen.

Um genügend Probanden zu bekommen habe ich schnell diehttp://weaselhunter.comWebsite aufgesetzt. Diese leitet lediglich auf einen Sammler für eine Mailing-Campaign weiter. Ich benutze im Hintergrund http://mailchimp.com/ und pflege damit die Mailingliste. Mailchimp ist etwas überdimensioniert. Daher wundert euch bitte nicht, dass die damit versandten Emails nicht so schick aussehen.

Sobald der Erhebungsclient fertig ist und das Design steht, sende ich euch einen Link zu. Ich erwarte, dass es Ende dieser Woche losgehen kann! Dann müsst ihr nurnoch den Anweisungen folgen. Ich bedanke mich bereits jetzt für eure Unterstützung!

Kommentar zum Open Space

Zwar ohne schickes Hemd - aber Uli Armbruster hat mich interviewt! Wir sprechen auf dem Openspace - über den Openspace. Genauer: Es war der .NET OpenSpace in Karlsruhe, der vom 06.07 - 07.07.2013 stattfand. Danke an die Organisatoren, die BlueHands (nicht zu verwechseln mit denen hier die den Teilnehmern ihre Räumlichkeiten zur Verfügung stellten.

Mehr Beiträge zum NET Open Space findet ihr in Ulis Blog: http://uliarmbruster.de/blog

Für besagte Studie könnt ihr euch hier anmelden: http://weaselhunter.com/

Developer Week 2013

Vom 24. bis zum 26. Juni 2013 fand die Developer Week 2013 in Nürnberg statt. Auch dieses Jahr durfte ich wieder als Sprecher und Hörer teilnehmen. Hochkarätige Sprecher und Vorträge zu den Themen Mobile, Web und .NET boten einen hohen Informations- und Unterhaltungswert, so dass wohl jeder auf seine Kosten kam.

Hier möchte ich - kurz und bündig - von meinen eigenen Impressionen berichten. Diese gliedere ich nach verschiedenen Themenkomplexen, anstatt sie chronologisch zu sortieren.

Übersicht

  1. Bulletpoints
  2. Die Besten Vorträge
  3. Sexismus
  4. Die Bühne gehört dir
  5. CQRS - Gaga?!
  6. Provokation
  7. Pro & Contra
  8. Danksagung

Bulletpoints

Ich kam bereits am Sonntag an und wohnte am Montag dann pünktlich um 9 der Keynote von Chris Rupp bei. Diese war ausgezeichnet und leitete die DWX angemessen ein. Chris Rupp ist eine ausgezeichnete Sprecherin - von ihren Folien war ich jedoch nicht so überzeugt wie von ihr als Person. Neben zufälligen Stockbildern hatten manche Folien zu viel "Bullet-Point" Inhalt, den man garnicht im Detail wahrnehmen konnte. Ich gab ihr später in der Speakerlounge dazu persönlich Feedback und kam zu dem Schluss, sie müsse eigentlich überhaupt ohne Powerpoint präsentieren.

Natürlich brauche ich ihr da nicht reinreden und vielleicht war das auch anmaßend von mir, aber meine Sicht der Präsentationswelt sollte sich später weiter bestätigen. Die langweiligeren Vorträge hatten viele Slides mit Bulletpoints - die besseren Vorträge verzichteten fast vollständig auf Bulletpoints. Ich selbst versuche seit einer Weile ohne Bulletpoints in meinen Präsentationen auszukommen. was soweit ganz gut klappt. Dazu gibt es einige Tricks, die aber nicht so schwer umzusetzen sind.

Tatsächlich wären viele Vorträge NOCH besser gewesen, wenn die Autoren und Vortragenden auf Bulletpoints verzichtet hätten. Darunter besonders der Vortrag von Christian Jakob mit dem Titel "Open/Closed für Einsteiger". Inhaltlich war alles einwandfrei, aber die Einleitung hätte kürzer sein können. Als aber Visual Studio aufging war alles vergessen und Christian überzeugte mit sauberen Argumenten und verbessertem Code. Für mich war sein Vortrag ein Highlight der DWX.

Weitere Positivbeispiele stellten auch die Vorträge von Jan Fellien und Roberto Bez mit ("Command & Conquer the segregation") sowie der Vortrag "Polystrukturierte Daten mit CQRS" von Philip Jander dar. Auch zu nennen sei Marius Schulz der in angenehmer Geschwindigkeit über Knockout.js präsentierte.

Die Besten Vorträge

Wie schon gesagt war der Vortrag von Christian eines meiner Highlights, aber der Vortrag von Philip Jander schlug sie alle um Längen. Es ging um Polystruktuierte Daten mit CQRS. Dabei gelang Philip der Kniff, das Command-Query-Responsibility-Segregation Pattern an einem praktischen Beispiel zu veranschaulichen, ohne dabei zu sehr ins falsche Detail zu gehen. Er schaffte es, dieses - sonst nur sehr abstrakt diskutierte Architekturpattern - sehr konkret greifbar zu machen.

Ich bin ein großer Fan der Wechselwirkung zwischen Theorie und Praxis, und in Sachen Praxis hat Philip einen sehr wichtigen Baustein geliefert. Er zeigte an einem konkreten Beispiel, wie mit Hilfe eines SQL Servers ein EventStore implementiert werden kann (indem man die relationale Natur des SQL ignoriert). Ich war über den Code, den Philip zeigte höchst erfreut, da dieser sehr "empathic" rüberkam. Verschiedene Prinzipien und Praktiken waren hier umgesetzt. Natürlich will ich mir hier nicht selbst die Lorbeeren aufsetzen, da ich niemals selbst an Philips Code mitgewirkt habe. Dennoch war ich froh, Code zu sehen, bei dessen Entwicklung die Lesbarkeit - bzw. "Sprechbarkeit" - ein wichtiger Aspekt gewesen sein muss. Ich selbst bin mir nun über die Antwort zu einer bisher offenengebliebenen Frage etwas sicherer: Empathic Code skaliert und kann auch in einem "Enterprise"-Kontext angewandt werden. Und das sehr gut.

Übrigens: Philip kam ohne Buzzwords aus. "Polystrukturiert" ist hier auch so zu verstehen - und trifft den Kern der Aussage wesentlich besser als der Begriff den andere oft verwenden: "BigData". Philip schaffte es, eine bedeutungsvolle begriffliche Unterscheidung einzuführen.

Sexismus

Gäääähhhnn... Ochhhh... Werden viele jetzt lesen... und schon keine Lust mehr haben. Aber mir wird das Thema immer wichtiger, aus verschiedenen Gründen. Ich war definitiv "geprimed" oder "voraktiviert", wie der Psychologe so schön sagt, durch meine Klausur zum Abschluss der Vorlesung "Genderforschung", die ich im Rahmen meines Psychologiestudiums belegt hatte.

Schlimm finde ich, dass viele das Thema als nervig empfinden und schon keinen Bock mehr auf das Thema haben. Und das bedeutet für mich leider: Die Idioten haben gewonnen.

Die Idioten? Das sind die, die im Rahmen von Hashtag-Aufschrei nur Mist beizutragen hatten. Wie beispielsweise der Stern, der sich auf einmal als Moralwächter gab. Selbsternannte Emanzen und "Pseudofemis" - die die Diskussion kapern und dafür sorgen, dass am Ende jeder nurnoch genervt den Twitterclient abschaltet. Willst du weiterlesen? Dann nicht hier - sondern hier: Ein Kommentar zum Sexismus. Allerdings kam das Thema am Abend der DWX auf und ich finde, es sollte nicht untergehen.

Die Bühne gehört dir

Nachdem am Montag Abend einige interessante Themen diskutiert wurden, lernte ich am Dienstag neue/alte Freunde kennen. Diese kannte ich teils von vergangenen Vorträgen. So kam ich dann dazu, einzuschätzen, wie am Montag mein Vortrag über Python verlaufen war. Ich selbst war mit meiner Performance höchst unzufrieden, was aber an verschiedenen Faktoren lag. Eigentlich war ja alles gut gelaufen - der Raum war gefüllt, die Präsentation klappte reibungslos - nur am Ende war ich etwas nervös und hätte noch etwas echten Code zeigen wollen. Was mich nervös gemacht hatte: Die Bühne. Auch der Herr von der Technik hatte dazu beigetragen. Um 15:00 sollte es losgehen, um 14:59 diskutierte Letztgenannter jedoch noch mit meinem Vorredner. Ich musste die beiden quasi von der Bühne scheuchen. Ich bekam in Sekundenschnelle das Micro - angetackert - mit der Aussage, dass gleich das Licht aus und das Micro anginge - und da war es auch schon geschehen. Ich fühlte mich an die Zeit während des Abiturs erinnert. Ich schauspielerte in der Theater-AG meines Gymnasiums und gegen das Licht der Scheinwerfer sehend kann man im Publikum niemanden erkennen - leider fühle ich mich jedes mal darauf angewiesen. Die Bühne schaffte unangenehme Distanz und der hektische Start machte mich bis zum Ende hin total nervös. Ging wohl trotzdem glatt, zumindest gab es kein vernichtendes Feedback.

Bis zu meinem Vortrag über Empathic Refactoring am Donnerstag sollte ich mich jedoch weiter in fast panische Präsentationsangst steigern. Eigentlich garnicht mein Ding. Entschuldigt, wenn ich euch damit auf die Nerven gegangen bin. Durch ein-zwei Kniffe konnte ich meine eigene Nervosität am Donnertag morgen abschwächen - ich bin gespannt auf die Videoaufzeichnung von meinem Vortrag, die ich natürlich hier posten werde.

Teil meiner Nervosität war, dass ich im größten Raum der Konferenz präsentieren sollte. An den Seitenwänden wurden neben der Bühne regelmäßig wechselnde Sponsorenlogos eingeblendet. Göthe sei Dank durfte ich diese während meiner Präsentation abschalten. Hier übrigens große Kritik an die Organisation: Ich sehe ein, dass Sponsoren wichtig sind, aber wenn sie sich auf diese Art in die Präsentation schleichen, finde ich das übergriffig und unangenehm. Ich habe keinen Teilnehmer der Konferenz getroffen, der darüber nicht unzufrieden war. Den meisten fiel auf, dass die Logos animiert waren - sie wechselten wohl alle (halbe)-Minute. Hier lässt sich fürs nächste Mal sicher ein besserer Kompromiss finden.

CQRS - GaGAFaldera?!?!

Weil Mike Bild ausfiel, erklärten Jan Fellien, Philip Jander, Carsten König und Ich uns bereit, eine Art OpenSpace Diskussion zum Thema CQRS zu leiten. Leider lief dies (in meinen Augen) nicht so glatt, wie geplant. Viele verließen den Raum, vllt. konnten sie nicht folgen. Durch die "Bühne" wurde eine Diskussion eher behindert. Spätere Diskussionen ergaben jedoch Folgendes:

Während der Sitzung kam Florian Sesser in den Saal. Ich kannte ihn vom Vorabend und hatte mir gemerkt, dass er sehr im Open-Source Bereich unterwegs ist. Aus der Open Source Welt - sprich Python, PHP, Linux/Unix, git, etc. bin ich gewöhnt, dass oft kleine, individuelle Tools bevorzugt werden und dass große, komplizierte Lösungen eher belächelt werden. Diese Perspektive auf CQRS hatte mich direkt interessiert - weshalb ich Florian unmittelbar aufforderte, auf der Bühne Platz zu nehmen und mit uns zu diskutieren (dieser Bitte kam er etwas missmutig nach). Er trug leider "live" nur wenig bei, äußerte jedoch später, wie sehr das Thema für ihn ein "WTF" - darstellte. Genau dies hätte mich eigentlich interessiert. Wir sprachen auf der Bühne von einem "schön umzusetzenden, leichten Architektur-Entwurfsmuster". Für Florian war dies wohl eher unsinniger Hokuspokus, von irgendwelchen Pfeifen, die einfach nur Statemachines nachbauen. Er verglich die abgesetzten "Events" mit OP-Codes eines Prozessors. Im Detail kann ich nicht alles wiedergeben - aber Florian hatte gar nicht so Unrecht. Oft erfinden wir das Rad einfach neu.

Ein weiteres Beispiel? SOLID-Code. Eigentlich gehts dabei ja nur um Objektorientierung... Zumindest war das so mein Gefühl. Aber dazu mehr im Artikel Solid - Das Rad neu erfunden?.

Provokation

Leider verließ ich die DWX am Donnerstag gegen Mittag. Die Keynote scheint sich aber gelohnt zu haben. Ralf Westphal verglich darin wohl TDD-loses Programmieren mit einem Methylamphetaminabhängigen - was viele wohl geschockt hat. Leider kann ich nicht genau wiedergeben, was er sagte (vllt. gab es einen Live-Stream! Es war immerhin die Keynote), aber von vielen Zuschauern wurde die Analogie als "geschmacklos" kommentiert.

Dazu kann ich nur sagen: Gut gemacht, Ralf! Es braucht vielleicht die Provokation und die schlimmen Bilder im Kopf, den Schock und das Extreme, dass manche endlich mal einen Unterschied feststellen. Als Consultant ist man oft darauf bedacht - möglichst politisch korrekt - bestimmte Standpunkte zu vermitteln. Manche wachen sonst einfach nicht auf oder fühlen sich angesprochen.

An eine Provokation erinnert man sich - nicht aber an das BulletPoint-Bingo ala "Meine Firma wurde 1998 gegründet"... Dazu gehört wohl auch viel Mut und ich bin höchst erfreut, dass Ralf den Mut gefunden hat, zu sagen was er denkt und die Aussage direkt, politisch unkorrekt und ohne Zuckerglasur zu präsentieren. Das würde ich mir von anderen öfter wünschen.

Abschließend möchte ich noch einige Stichworte kommentieren:

Pro

Contra

Damit möchte ich mich ganz herzlich bei allen bedanken, aber ganz besonders bei

Flo Bender, Kerstin Hartmann, Annegret Behncke, Tala Otte, Steffen Monarth, Tilman Börner, Golo Roden, Andreas T., Carsten König, Johannes Hoppe, Jan Fellien, Roberto Bez, Laurin Stoll, Mike Bild, Kostja Klein, Florian Sesser, Philip Jander, Torsten Weber, Hans-Christian Otto, Hendrik Lösch, Patrick Koglin, Marius Schulz, Jonathan Weiss, Christian Jakob,

...und bei allen, die ich hier vergessen habe. Abschließend möchte ich noch alle kennen, die mich grüßen ;)

*) "Meth" oder "Crystal" ist eine Droge, die bei Dauerkonsum auch kurzfristig zu extremem körperlichem Verfall führt.

SOLID - Das Rad neu erfunden?

In seinem Vortrag Open/Closed für Einsteiger refaktorisierte Christian Jakob ein wenig Code, um dem Open/Closed Prinzip (OCP) Genüge zu tun. Er verwendete dazu die Technik Replace Conditional with Polymorphism, die in Martin Fowlers ausgezeichnetem Buch "Refactoring" beschrieben ist. Dabei wird beispielsweise ein Switch-Case Statement in eine Klassenhierarchie übersetzt. Mir fiel dabei auf, dass für das Refactoring die Einhaltung von OCP das Ziel darstellte - aber die anderen SOLID-Prinzipien ignoriert wurden (obwohl sie teils auch erfüllt waren)! Dies möchte ich daher an dieser Stelle weiterführend kommentieren.

Polymorphic vs. Conditional

Beispielsweise wird

csharp
public decimal CalculateSalary() 
{
    switch (_employeeType) 
    {
        case PROGRAMMER:
            return getSalary();
        case CONSULTANT:
            return getSalary() * 2;
        case INTERN:
            return getSalary() / 2;
        default:
            ...
    }
}

zu:

csharp
public decimal CalculateSalary() 
{
    return _empolyee.getSalary()
}

public interface Employee { decimal getSalary(); }

// Auszug
public class Intern : Employee { 
    ... 
    public decimal getSalary() 
    {
        return _salary / 2;
    }
}

public class Consultant : Employee {...}
public class Programmer : Employee {...}

Wie man sieht ist die eigentliche Logik im Switch-Case-Statement einer einzigen Zeile gewichen. Mehrere Klassen wurden erstellt, die ein Interface implementieren. Dieses liefert abhängig vom Typen, auf dem es aufgerufen wurde, einen anderen Wert. So kann die Klasse Programmer in der Methode getSalary einfach das normale Salary zurückgeben, während der Intern beispielsweise nur die Hälfte des normalen Salärs erzeugt. Die "CalculateSalary"-Methode bekommt von alldem nichts mit. Bei der ursprünglichen Implementierung ist dies anders. In einem neuen Fall müsste das Switch-Case Statement verändert werden. Es ist also nicht geschlossen gegenüber Veränderungen - wie vom OCP gefordert.

Die einzelnen Fälle des Switch-Case-Statements wurden mit einer eigenen Klasse ersetzt. Das Open/Closed-Principle wurde dadurch umgesetzt, da das Hinzufügen eines neuen Falles - also einer neuen Klasse - die anderen Fälle nicht berührt. Fassen wir zusammen: Das Switch-Case-Statement verletzt das OCP - eine saubere Klassenhierarchie erfüllt das OCP. Diesen Punkt konnte Christian in seinem Vortrag hervorragend zeigen.

Vervollständigung

Interessant ist an diesem Refactoring, dass es - quasi durch die Hintertür - weitere SOLID-Prinzipien umsetzt - oder zumindest für später vorbereitet. Zunächst lässt sich die Testbarkeit des Codes diskutieren. Diese ist gestiegen - darauf ging Christian auch ein. Das Switch-Case-Statement erfordert einen Test mit mindestens 4 Fällen - die Klassen benötigen jeweils nur einen Test mit und einem Fall (fürs erste, bzw. für die gleiche Testabdeckung.). Vorteil ist, dass die Testfälle voneinander isoliert sind und so ein feiner granuliertes Feedback ermöglichen.

Aber welche SOLID-Prinzipien erfüllt der Code weiterhin? Wir erinnern uns: Single Responsibility (SRP), Open/Closed (OCP), Liskov Substitution (LSP), Interface Segregation (ISP), Dependency Inversion (DIP)

Wie trifft das auf den Code zu?

Zusammenfassend lässt sich also sagen: Wir haben nur auf OCP geachtet und der Code ist gesamtheitlich "solider" geworden. Tolle Sache!

Das Rad neu erfunden?

Was aber vielen nicht aufgefallen ist: Die Implementierung lässt sich aus einem viel basaleren Standpunkt betrachten. Ich brauche garnicht SOLID in die Gegend husten, wenn noch nicht die eigentliche Natur des Codes diskutiert wurde. Nicht nur ist das Switch-Case-Statement weniger "SOLID" - es ist auch nicht objektorientiert! Ein Switch-Case Statement ist eigentlich prozedural. Eine Art Durchlauferhitzer. Oben ein Flag rein, unten eventuell ein Ergebnis raus. Wie kontert das die Objektorientierung?

In der Uni lernen wir leider immer nur, dass ein BMW ein Auto ist; dass Katze und Hund Säugetiere sind. Und damit endet die OO-Diskussion. Vererbung wird zu sehr an der "Vererbungsmetapher" aufgehalten und zu sehr auf Eltern-Kind-Relationen reduziert. Die der wichtige Teil, der aber mit OO zu tun hat, ist der Polymorphismus.

Abhängig von ihrem Typen kann die konkrete Instanz einer Klasse, bei gleichem äußerlichen Aussehen, ein anderes internes Verhalten zeigen. Das wurde im Beispiel auch umgesetzt - man bekommt einen Employee (anstatt eines TypeCodes). Welcher genau das ist, interessiert eigentlich nur am Rande. Wichtig ist nur, dass dieser die entsprechende Methode mitbringt, die aufgerufen werden soll. Durch Typing auf das Interface wird dies vom Compiler auch geprüft. **)

Fazit

Persönlich lerne ich daraus: Bevor wir über "höhere" Themen wie SOLID diskutieren, sollten wir uns an objektorientierte Grundprinzipien erinnern. Ich glaube, dass diese oft nicht richtig umgesetzt wurden und die meisten Probleme, die man mit Code hat, dadurch entstehen, dass prozedurales bzw. auch imperatives Denken die Implementierung bestimmt. Dies leite ich unter anderem daran ab, wie viele objektorientierte Programmierer Patterns wie beispielsweise das NullObjekt-Pattern als per se unsinnig empfinden.

So geht es mir übrigens auch mit Domain Driven Design. Die Idee ist vielfältig, aber die Aspekte Modellierung und Domänenorientierung sind für mich - wie im "Evans" beschrieben - fast mit OO gleichzusetzen.

Ich glaube, dass Test-Driven Development und die Funktionale Programmierung, sowie Ansprüche auf Parallelisierung in Zukunft neue Reflektion über die grundlegenden Paradigmen provozieren werden.

*) Ich finde das LSP recht schwer zu verstehen und bin für Berichtigungen dankbar, sollte ich hier Unfug geschrieben haben!

**) In dynamischen Sprachen braucht man nicht einmal ein Interface dafür.

Falsche Freunde

Ich freue mich in letzter Zeit immer wieder über Kollegen und Freunde, die mir berichten, dass sie gute Erfahrungen mit Empathic Code machen konnten. Dabei fallen mir jedoch ein paar Dinge auf, die wohl eine Richtigstellung erfordern.

Wieseln - Weaseling

In meinem Artikel in der dotnetpro schlug ich vor, unbekannte Konzepte zu 'wieseln'.

Ersetzen Sie alle Weasel Words in einem Bezeichner durch Weasel. FieldFunctionManager wird dann zu FieldWeasel. Nun trägt die Klasse einen lächerlichen, nichts aussagenden Namen, der vermittelt, dass die Klasse zu viel tut und refaktorisiert werden muss.

Ähnlich wie bei einem TODO Kommentar sollte klar sein, dass dies nur eine Notlösung ist. Die eigentliche Lösung besteht darin, das Konzept, das von der Klasse implementiert wird sauber zu identifizieren und zu benennen. Weaseln sollte nur im letzen aller Fälle vorgenommen werden, also wenn man wirklich noch nicht weiß, wohin mit der Klasse, oder ob das Konzept sauber ist. Dies sollte sich aber nach wenigen weiteren Refaktorisierungen ergeben, sodass das Wort entfernt werden kann. Es ist übrigens nicht notwendig, die Klasse oder die Funktion zu wieseln. Man kann auch andere Unsinnswörter verwenden, beispielsweise - Wobble - Utzelglutzel - Ötzelbrock - WuggawuggaWulliwulli

oder eben jeden beliebigen Buchstabensalat (qwertzuiopasdfghjkl). Es sollte nur markiert werden: Hier ist was faul. Merkt euch das Gedicht der Loreley:

Ich weiß nicht was soll es bedeuten
Dass ich so traurig bin;
Der Code ist wirklich ganz furchtbar,
Die Bezeichner ergem kein' Sinn

Weasel Word ist nicht gleich Weasel Word

Die erste Heuristik von empathischem Code ist immer die Vorlesbarkeit. Der Code sollte aussprechbar sein. Besonders beim Pair Programming wird dies klar. Die Frage ist, wie Aussprechbarkeit definiert wird. Oft kann es nützlich sein, Füllwörter in Bezeichner einzufügen. Das ist die genaue Gegenbewegung zur Entfernung von Weasel Words - Weasel Words einbauen und ist daher nur mit großer Vorsicht zu genießen. Besonders betroffen sind hier "Party Hats" wie My, It, A oder An, The, This und That. All diese Begriffe sollten dem Sprachfluss dienen und nicht unnötig den Code verwässern. Dazwischen liegt aber ein feiner Grat:


class myThread (threading.Thread):
    pass
    

Quelle

Hier wird 'my' nur verwendet, um einen Thread zu implementieren, und dessen Namen von der ursprünglichen Thread Klasse zu unterscheiden. Der Eintrag selbst versucht das Konzept des Threading in Python näher zu bringen, daher besteht keine Notwendigkeit, zusätzliche Semantik in den Klassennamen einzubauen. Für ein Beispiel ist sowas OK, ich fände aber "ExampleThread" oder "TestThread" da wesentlich besser, da diese beinhalten, dass man ja nur rumfummelt und es eigentlich egal ist, was die Klasse letztendlich erledigt. 'My' suggeriert Besitz. Ich frage mich dann immer, wer denn das I zu dem My ist. Also wem gehört die Klasse; aus wessen Perspektive wird das 'My' geäußert? Gehört sie dem Entwickler, der gerade vor dem Monitor sitz? Dem Entwickler, der die Klasse entwickelte? Dem aktuellen Modul, Stack oder Loop, indem sie sich befindet? Oder ist Python der Besitzer? Wenn das 'deins' ist, darf ich das dann anfassen? Wer ist hier wer? Um solche Fragen zu vermeiden, sollte auf 'My' verzichtet werden. The und An sind da etwas besser, aber haben ähnliche Probleme. Wie sieht's jedoch mit dem I aus?

public Templates(IKnowIfTemplateIdMatchesTheColor colorService)
{
    _colorService = colorService;
}

Hier wird klar, dass colorService das Ding ist, was durch I beschrieben wird. Die Klasse (bzw. das Interface) weist darauf hin, was sie anbietet. Idealerweise könnte man darauf verzichten, aber Empathic heißt auch, nicht einfach jede Konvention zu verteufeln. Daher wird so ein Kompromiss geschlossen, der die .NET Konventionen beibehält und ihnen gleichzeitig eine sinnvolle Semantik abverlangt. Nebenbei: Das IDoSomethingForYou-Konzept geht übrigens auf Udi Dahan zurück (Source).

Empathic != Verbose

Die oben gezeigte Implementierung ist leider auch noch nicht komplett wieselfrei oder gar empathic, da sie weiterhin Begriffe auf unterschiedlichen Abstraktionsniveaus beinhaltet. Wir finden in 'IKnowIfTemplateIdMatchesTheColor'.

Die suggerierte Operation ist 'to know'. Dies bezieht sich aber in einem programmierten Kontext darauf, dass einfach nur "Wissen" abgefragt wird. Es lässt sich also ableiten, dass die Operation nicht "wissen" ist, sondern der Abruf von Wissen, also Zugriff auf Properties. Es wurden also Attribute mit Methoden verwechselt. Für ein Interface fatal, da es eigentlich nur Methoden beinhalten sollte. Getter und Setter sind zwar Methoden, haben aber auf einem Interface nichts verloren. Damit weist der Begriff auf eine Verletzung des Law Of Demeter hin (bzw. Tell, don't ask) - es wird auf die privaten Informationen einer Datenstruktur zugegriffen. Prozeduraler Code ist im Anmarsch.

Ein weiteres Verb ist 'to match'. Dies stellt die eigentliche Operation dar. Das Interface sollte besser heißen I Match Templates with Colors oder IMatchTemplateAndColor oder sogar IMatchATemplateWithAColor . Der Begriff Id weist ohnehin auf ein unwichtiges, technisches Detail hin, da das Konzept 'Template' ist. Das weist darauf hin, dass es durch eine Id identifiziert wird und es sich somit wohl um eine Entität im DDD Sinne handelt. Dieses Detail ist auf dieser Ebene der Abstraktion unwichtig.

Der Code lässt sich aussprechen. Sauber ist er deswegen noch lange nicht. Es lassen sich aber verschiedene Informationen aus dem Gesprochenen ziehen. Die Aussprechbarkeit ist kein Endzustand, sondern eine Heuristik, also eine Methode um unter Unwissen oder Unklarheit zu einer guten Lösung zu kommen (altgr. εὑρίσκω heurísko: "ich finde").

Ähnlich ist es im folgenden Code:

private ITemplate FindMeATemplateForThis(FormData input)
{
    return _colorService.TemplateIdMatchesTheColor(input.color, input.header);
}

Der Methodenname FindMeATemplateForThis benötigt kein 'Me', da Code nach wie vor nicht irgendwelchen Autoren zugewiesen werden kann, besonders wenn ein Team daran arbeitet. 'A Template' hingegen passt relativ gut in den Sprachfluss. Das This wiederum ist unnötig. Auch Find ist nicht unbedingt relevant, sofern das Konzept sauber abgebildet ist:

Statt

class Templates
{
    private ITemplate FindMeATemplateForThis(input) 
    {
        // ...
    }
}

Wäre hier sogar folgendes ausreichend:

class Templates
{
    private ITemplate For(input) 
    {
        // ...
    }
}

Selbstverständlich kann es zu einer Verwechselung mit dem For-Keyword kommen, sodass ein Entwickler denkt, dass über For die Template-Collection iteriert wird. Zusätzlich kann also die Operation weiter codiert bleiben, also beispielsweise FindFor oder einfach Find.

When I open a solution...

And check it for weasel words...

Aliens!

Vier Jahreszeiten

tl;dr

Es gibt vier Wege, INotifyPropertyChanged für MVVM-ViewModels zu implementieren:

Sourcecode: https://github.com/cessor/ViewModel

Disclaimer:

Aufpassen - Weasel Words ahead! Ich verwahre mich normalerweise gegen Begriffe wie Model oder ViewModel in meinem Code. Für dieses Beispiel ist es jedoch sinnvoll, sie drin zu lassen. Warum erkläre ich am Ende des Artikels genauer.

MVVM

Das von Microsoft spezialisierte Presentation Model Pattern, vereinfacht die Implementierung von WPF Anwendungen und ist als Model-View-ViewModel (MVVM) bekannt.

Das ViewModel stellt eine Datenstruktur dar, die zu bestimmten Ereignissen an die View gesendet wird, etwa wenn sich ein Wert ändert. Die View aktualisiert dann alle Werte, die sich geändert haben. Der Entwickler muss entscheiden, ob und wann das Update der View durchgeführt werden muss. Dazu gibt es, grob gesagt zwei Möglichkeiten:

  1. Full Update - Bei der Änderung eines Wertes wird ein neues ViewModel erzeugt und an die View gesendet. Alle Werte werden aktualisiert.

  2. Delta Update - Bei der Änderung eines Wertes wird die View benachrichtigt. Nur der geänderte Wert wird aktualisiert.

Die Implementierung von MVVM sieht vor, dass Updates nach der zweiten Methode durchgeführt werden. Nur die tatsächlich geänderten Werte werden aktualisiert.

Die Spezialität des MVVM Musters ist, dass es, eingebettet in WPF- oder Silverlightanwendungen, auf einen spezifischen Mechanismus zurückgreifen kann, der das Implementieren des Updatemechanismus vereinfacht - das sog. DataBinding.

Die in XAML beschriebene View verwendet Erweiterungen im Markup, um Daten aus Objekten zu extrahieren. Das ViewModel wird als "DataContext" an die View gebunden. Ändert sich ein Wert auf dem ViewModel (diese Änderungen entstehen durch das eigentliche "Model"), so löst das ViewModel ein Ereignis (Event) aus. Der DataBinding-Mechanismus reagiert auf diese Events und aktualisiert die einzelnen Eigenschaften der View.

Damit diese Bindung funktioniert, muss ein standardisiertes Event ausgelöst werden. Dazu muss das ViewModel das Interface 'INotifyPropertyChanged' implementieren. Dies veröffentlicht den Delegaten

public event PropertyChangedEventHandler PropertyChanged;

Das ViewModel soll diesen Delegaten auslösen, sobald sich ein Wert geändert hat. Ohne Properties sieht das ViewModel so aus:

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler == null) return;
        handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

Um eine Racecondition beim Auslösen des Events zu verhindern, wird hier eine Methode verwendet, die zunächst die Delegatenaufrufliste kopiert und dann durch die Kopie das eigentliche Event auslöst. Der Methode wird ein Stringwert übergeben, der für die View relevant ist - anhand des Namens weiß sie, welcher Wert sich geändert hat und welches Steuerelement aktualisiert werden muss.

Wie wird nun auf die Änderung von Werten reagiert?

1. Die Naive Implementierung

Das ViewModel könnte einen Text anzeigen, etwa so:

private string _label = string.Empty;
public string Label
{
    get { return _label; }
    set 
    {
        if (_label == value) return;
        _label = value;
        OnPropertyChanged("Label");
    }
}

Nur wenn sich der Wert auch tatsächlich geändert hat, soll das Event ausgelöst werden. Darüber entscheidet die Guard-Clause am Beginn des Setters. Falls der Wert tatsächlich geändert wurde, wird das Update geschrieben und danch das Event ausgelöst.

Durch die hier gezeigte Implementierung entstehen jedoch schnell Redundanzen. Jedes Property wird immer die Dreifaltigkeit aus Guard Clause, Änderung und Event implementieren müssen. Gegenüber normalen Settern, die meist mit einer Zeile auskommen, ist dies ein enormer Overhead, der sich in starker Codeduplikation niederschlägt.

Eine Methode schafft Abhilfe.

2. Ein generalisiertes ViewModel

public void Set(ref T field, T value, string propertyName) 
{
    if (EqualityComparer.Default.Equals(field, value)) return;
    field = value;
    OnPropertyChanged(propertyName);
}

Durch eine generische Methode lässt sich der Setter-Vorgang typsicher, jedoch generalisiert auf jeden beliebigen Typ (generisch eben), implementieren.

Die generische Guard-Clause verwendet einen Equality-Comparer, um sowohl für primitive als auch Referenztypen die entsprechenden Vergleichsmethoden aufzurufen. Danach wird der eigentliche Wert gesetzt und das Event ausgelöst.

Die Implementierung des Setters beschränkt sich damit auf eine Zeile:

private string _label = string.Empty;

public string Label
{
    get { return _label; }
    set 
    {
        Set(ref _label, value, "Label");           
    }
}

Der schlaue C# Compiler denkt mit - da der generische Parameter am Setter aus dem Typen von Label und Value abgeleitet werden kann, braucht er nicht explizit angegeben werden. Das vereinfacht die Syntax erheblich. Es muss also nicht lauten

Set(ref _label, value, "Label");

sondern

Set(ref _label, value, "Label");   

ist vollkommen ausreichend.

Eine Besonderheit der Implementierung ist der field-Parameter, der als Referenz übergeben wird. Der ref-Qualifizierer gibt an, dass Änderungen sich nicht auf eine lokale Kopie eines Wertes beziehen (wie beim value-Parameter), sondern dass eine Variable außerhalb des Scope der Methode verändert wird. So ist es möglich, dass die generische Methode tatsächlich den eigentlichen Feld-Wert (_label) verändert.

Sowohl der Delegat und dessen Auslöse-Funktion als auch die Set-Methode stellen Infrastrukturcode dar. Das ViewModel sollte als Datenstruktur möglichst schlank bleiben und nur die für die View wichtigen Daten enthalten. Durch eine Basisklasse lässt sich der Code weiter vereinfachen. Dies stellt eine "Separation of Concerns" dar.

public abstract class ViewModel : INotifyPropertyChanged 
{
    protected void Set(ref T field, T value, string property) 
    { /* ... */ }
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName) { /* ... */ }
}

public class MainViewModel : ViewModel 
{
    private string _label;
    public string Label { get; set { /* ... */ }}
}

Das Prinzip "Composition over Inheritance" ist hier leider nicht einhaltbar, da das DataBinding erfordert, dass das ViewModel das Interface direkt implementiert. Wenigstens ist auf diese Art und Weise das ViewModel frei von Infrastruktur und beinhaltet nur noch Properties, wie es sich für eine ordentliche Datenstruktur gehört.

Problematisch ist jedoch weiterhin, dass ein String verwendet wird, um den Namen des Property anzugeben. Damit die View versteht, welches Property geändert wurde, muss sie den Namen des Datenfeldes kennen. Ein String hat hier viele Nachteile - er kann beliebige Werte annehmen und ist sehr fehleranfällig. Was wenn jemand statt

Set(ref _label, value, "Label");           

die Methode falsch aufruft, etwa so?

Set(ref _label, value, null);

Oder so?

Set(ref _label, value, "");   

Der Compiler wäre hiermit einverstanden - der Fehler würde sich erst zur Laufzeit bemerkbar machen. Eigentlich ein gutes Argument um Tests zu schreiben, aber so lange hier Strings verwendet werden, benötigt man sehr viele Testfälle, und beim Anlegen neuer Properties wird man auch nicht vom Compiler unterstützt. Das muss doch besser gehen!?

3. Typsicherheit durch Expression-Trees

Anstatt Typsicherheit sollte hier vielleicht besser von Feldsicherheit gesprochen werden. Die Datentypen sind bereits sicher, da die Methode generisch ist, aber der Feldname ist es leider nicht. Wie lässt sich dieser vom Compiler prüfen? Hier helfen Lambda-Expressions.

public string Label
{
    ... 
    set 
    {
        Set(ref _label, value, () => Label);           
    }
}

Hier wird dem Setter eine Funktion übergeben. Die Funktion hat keine Parameter, aber gibt einen Wert vom selben Typen zurück, den auch _label und value haben. Hier sagen wir der Funktion, dass sie den Wert von Label zurückgeben soll.

Das ist eigentlich erst mal contraintuitiv (dt.: vollkommen unsinnig). Wieso sollten wir den Wert von Label als Parameternamen übergeben? Die Antwort wird klar, wenn man die Implementierung der Set-Methode betrachtet:

public void Set(ref T field, T value, Expression> property)
{
    string propertyName = ResolveMemberNameFrom(property);
    Set(ref field, value, propertyName);
}

Die alte Set-Methode bleibt wie gehabt. Damit der Notify...-Delegat ausgelöst werden kann, benötigt er ohnehin den Namen als String. Es soll nur die Fehleranfälligkeit für übergebene Werte von außen minimiert werden. Daher wird die ursprüngliche Set-Methode auf private gesetzt und dann eine Public-Version überladen. Diese akzeptiert statt eines Strings eine "Expression".

Eine Expression ist ein Objekt, das einen Ausdrucksbaum kapselt. Hier ist der Ausdrucksbaum vom Typen "Func", also handelt es sich um eine Funktion ohne Parameter, die aber einen Wert (im Beispiel ein String) zurückgibt. Aus dem Ausdrucksbaum kann der Name des Properties extrahiert werden. Dies geschieht in der Resolve-Member-Name Methode:

private string ResolveMemberName(Expression> property)
{
    return ((MemberExpression)property.Body).Member.Name;
}

Zunächst wird die generische Expression auf eine MemberExpression gecastet. Daraufhin ist der Name des Members ("Label") abrufbar. Der Aufruf der Set-Methode

Set(ref _label, value, () => Label);           

erweckt also den Anschein, dass der Wert von Label ausgelesen wird, stattdessen greifen wir aber auf den Namen des auszulesenden Properties zu. Auch hier machen wir uns eigentlich einen kleinen Compiler-Trick zunutze. Korrekter Weise müsste der Code nämlich wie folgt aussehen:

public class MainViewModel : ViewModel
{
    private string _label = string.Empty;

    public string Label
    {
        get { return _label; }
        set 
        {
            Set(ref  _label, value, () => this.Label);           
        }
    }         
}

Eigentlich wird hier im Delegaten eine Closure erzeugt. Aus dem Scope der Klasse bzw. der Set-Methode wird auf die für sie sichtbaren Objekte zugegriffen. Eines davon ist der implizite This-Pointer, damit kann auf die Properties der Klasse zugegriffen werden.

IntelliSense bietet nun Hilfestellung, wenn es um das Ausfüllen der Set-Methode geht. Es ist nicht mehr möglich, einfach Null oder beliebige String-Werte zu übergeben. Es muss sich schon um ein Property der implementierenden Klasse handeln.

Leider ist auch diese Implementierung nicht ganz abgesichert. Es wäre beispielsweise gültig, folgende Implementierung vorzunehmen:


public class DialogViewModel : ViewModel
{
    private string _text = string.Empty;

    public string Text
    {
        get { return _text; }
        set 
        {
            Set(ref  _text, value, () => Text);           
        }
    }

    private string _caption = string.Empty;

    public string Caption
    {
        get { return _caption; }
        set 
        {
            Set(ref  _caption, value, () => Text);           
        }
    }
}

Der Teufel steckt im Detail. Text und Caption sind vom selben Typen, also meckert der Compiler nicht, wenn die Methode so aufgerufen wird. Wenn sich nun Caption ändert, wird die Guard Clause und der Setter korrekt ausgeführt, aber leider benachrichtigt das ausgelöste Event die View über eine Änderung des falschen Werts - nämlich Text - dabei wurde Text gar nicht geändert.

Auch hier helfen wieder nur Tests, die Laufzeitfehler isolieren. Wieder einmal erkennen wir: Nur weil's baut heißt es nicht, dass es funktioniert.

4. CallerMemberName-Attribute Power in .NET 4.5

Wurde das WPF Projekt bereits auf .NET 4.5 umgestellt, so bieten die Runtime und der C# Compiler ein sehr nettes Feature - das sog. CallerMemberName-Attribute. Dieses befüllt einen optionalen Parameter in einer Methode automatisch mit dem Namen der aufrufenden Methode. Der Aufruf wird dadurch minimiert:

public string Label { set { Set(ref _label, value); } }

Hoppla, haben wir da nicht was vergessen? Wo sagen wir der Set-Methode denn nun, dass sie die View benachrichtigen soll, einen frischen Wert aus dem Label-Property zu ziehen?

Wir tun dies, allerdings nicht implizit. Die Set-Methode hat sich geändert, jedoch nicht der aufrufende Code. Interessanter Weise haben wir statt einer Expression nun wieder einen String. Dieser ist als optionaler Parameter implementiert. Er hat also einen Default-Wert und man kann ihn sich beim Aufruf sparen. Daher ist der Aufruf von Set auch so kurz.

Die Set-Methode in der ViewModel-Basisklasse sieht dann wie folgt aus:


using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
public class ViewModel : INotifyPropertyChanged
{
    public void Set(ref T field, T value, [CallerMemberName] string propertyName = "")
    {
        if (EqualityComparer.Default.Equals(field, value)) return;
        field = value;
        OnPropertyChanged(propertyName);
    }
    ... 
}

Wird die Methode aufgerufen, so füllt die Runtime den propertyName Parameter automatisch mit dem Namen der rufenden Funktion. In diesem Falle ist der Name der Funktion gleich der Name des Properties - sehr praktisch.

Das spart Code, reduziert Duplikation und verhindert Fehler. Auch die letzte Implementierung sollte getestet werden. Zwar verhindert die Runtime irgendwelche irren Fehlerfälle, jedoch sollte der Test die Implementierung explizit zu machen - es reicht eine kleine Fixture mit einem Case, der dokumentiert, dass das Feature verwendet wurde. Impliziter Code ist immer schwierig zu verstehen als expliziter Code.

Diskussion

Mambo #5

Es gibt noch eine weitere Möglichkeit, um noch weniger Code zu fabrizieren: durch Aspektorientierte Programmierung (AOP). Durch AOP wäre es möglich, einfach ein Auto-Property zu verwenden, anstelle eines Property mit Backing-Field und dieses mit einem Code-Attribut zu versehen.

Durch AOP könnten sogar die Ableitung von der Basisklasse und der Aufruf der Set-Methode wegfallen. Leider ist dies in C# nicht von Haus aus möglich und ein Framework müsste eingeführt werden, beispielsweise PostSharp.

Nachteilig daran ist jedoch, dass PostSharp Lizenzgebühren fordert und den Build verlangsamt. Die weiter oben genannten Lösungen sind quasi Kostenlos.

Vade retro, satanas!

Besonders die letzte Implementierung ist interessant, aber ich kann schon einige Leser die Köpfe schütteln sehen. Sie verwendet ein Feature der .NET 4.5 Runtime, um den Namen des Properties automatisch zu übermitteln. Das ist weniger explizit als die Angabe des Properties als Expression, jedoch auch weniger fehleranfälliger, weil es Redundanzen beseitigt, weil das Property nicht seinen eigenen Namen angeben muss. Nicht und bedingt für jeden Geschmack geeignet, aber doch sollte man neue Features nicht kategorisch ablehnen, sondern eher ausprobieren, was man mit ihnen anstellen kann. Wenn es auf Dauer nicht klappt, kann man immer noch die alte Implementierung verwenden.

Als mein Freund @marcells mich darauf hinwies, dass ich die Set-Methode besser mit Expressions implementieren könne, zögerte ich zunächst. Ich hatte zu dem Zeitpunkt in meiner Solution ein ViewModel mit 4 Properties. Der Stringparameter stellte kein Problem dar. Dennoch habe ich mich schließlich überzeugen lassen und die Version mit Expressions eingebaut. Keine Angst vor neuen Features.

Weasel Words

Um das Beispiel zu veranschaulichen benutze ich Weasel Words wie "DialogViewModel". Eigentlich ist das Gift, es hilft hier aber für das Beispiel, Parallelen zu ziehen.

Für die Basisklasse ist der Begriff ViewModel in Ordnung. Sie hat keinerlei Schnittstelle mit der Domäne und soll nur die Notify-Infrastruktur abbilden. Sie bildet somit eine Notwendigkeit des Systems ab und dient nur der Implementierung des Patterns. Ein anderer Titel als ViewModel wäre zwar angebracht, aber im Zweifelsfall ist es sinnvoller in den Konventionen zu bleiben. Es ist zwar nicht schön, aber Model-View-ViewModel heißt nun mal in der Community so, auch wenn es nicht wieseliger geht. Bei allem Hass gegen Weasel Words sollte man nicht vergessen, dass Konventionen auch ihren Nutzen haben. Hier ging es um die Implementierung von INotifyProperty-Changed und nicht um einen Rant wie ungünstig der Titel des Pattern gewählt ist.

Beispielprojekt

Ich habe ein Beispielprojekt erstellt, dass alle drei Klassen getestet und vollständig veranschaulicht. Es kann hier heruntergeladen werden:

https://github.com/cessor/ViewModel

Update, 02. November 2012

Die beste Lösung ist ohnehin Code, der nicht geschrieben wird! Steve Wagner und David Tanzer wiesen auf Simon Cropps NotifyPropertyWeaver hin, der automatisch den Eventaufruf generiert.

Don't Kill my Cat

Jan Fellien dokumentiert in seinem Blogartikel "Don't kill my cat" die Session zum Thema Legacy Code am Developer Open Space, der vom 19.10. - 21.10.2012 in Leipzig stattfand. Am witzigsten und eingängigsten war wohl die Metapher mit der Katze. Jan dokumentierte sie so:

“Stell dir vor ein Freund bittet dich darum, während seins Urlaubes seine Blumen zu Hause zu gießen. Beim ersten Aufschließen musst du feststellen, dass die Wohnung total dreckig und vermüllt ist. Weil es ein Freund ist, möchtest du ihm einen Gefallen tun und räumst auf. Das dies einige Zeit in Anspruch nimmt, vertrocknen die Blumen und auch das Füttern der Katze vernachlässigst du total. Am Ende der Aktion steht eine super aufgeräumte Wohnung, vertrocknete Pflanzen und eine tote Katze. Beim nächsten Mal wird dich dein Freund, falls ihr noch Freunde seid, nur noch in aller größter Not mit den Worten bitten: ‘… und bring die Katze nicht um’”.

Leider ist hier nicht ganz korrekt wiedergegeben, wie die Metapher von mir gemeint war! Es mag aber durchaus sein, dass dies nicht von allen Teilnehmern aufgenommen wurde. Jans Auslegung der Metapher hat auch ihre Daseinsberechtigung.

Es ist eher so: Man kommt an und die Katze ist schon tot. Nicht das Aufräumen hat sie getötet.

Das Original

Ich führte an, was @JohannesHoppe mir einst vorwarf, als er kommentierte, dass ich oft ungefragt Refaktorisierungen an (seinem ;) Legacy/Brownfield Code vornähme. Aus einer wirtschaftlichen Perspektive ist dies nämlich fatal.

Er erklärte (frei wiedergegeben):

Wenn du einfach irgendwo Code aufräumst ist das nicht sinnvoll. Das ist wie wenn ich in Urlaub fahre und dich bitte, meine Blumen zu gießen. Wenn ich aber wiederkomme, ist alles total umgestellt, und du hast ungefragt aufgeräumt. Darum habe ich dich nicht gebeten.

Da ich, ohnehin oft sehr übertrieben Beispiele untermale und auch durch die Stimmung am Open Space sehr aufgeheizt war, fügte ich mehrere Bilder hinzu und untermalte die Situation krasser, als sie im Original auftrat.

Ich beschrieb dabei, dass die Wirklichkeit oft anders aussieht. Man wird gebeten die Blumen zu gießen. Aber bei Ankunft in der Wohnung kann man nicht die Blumen gießen. Die Wohnung ist eine Messie-Wohnung. Man kann sich vor Müll und Dreck kaum retten geschweige denn den Weg zu den Blumen finden, die man gießen soll. Hat man, vorbei an alten TV-Zeitschriften, Pizzakartons und 2 kaputten Mikrowellen, sich einen Weg durch den Abfall gebahnt, zu der Stelle, wo die Blumen sind, so erkennt man, dass die Blumen schon lange verwelkt sind und auch die Katze tot ist.

Die Metapher sollte also vermitteln, dass der Freund zwar meint, sein Problem zu kennen (Abwesenheit durch Urlaub) und einen beauftragt, dieses zu lösen (Blumengießen, Fische und Katze füttern), man bei Ankunft aber merkt, dass das nicht das Problem ist. Die Blume ist verwelkt und die Katze ist tot. Natürlich kann man nun Wasser auf die tote Blume kippen. Aber damit ist niemandem geholfen.

Vielmehr sollte man analysieren, was nicht stimmt. Die Messiewohnung weist auf eine psychische Störung hin. Der Kunde denkt, die Lösung für sein Problem sei das Blumengießen, doch in Wirklichkeit ist die Lösung für seine Probleme eine Psychotherapie, also eine Behandlung an der Wurzel.

Als Freund kann man sich nun entscheiden, was man tut.

Die Bedeutung für den Entwickler

Übertragen auf den Beruf als Consultant für Entwicklung ist das ähnlich. Meist wird man mit einem thematischen Bezug aufgesucht (konkretes Projekt, spezielle Anforderungen, Kenntnisse). Der Kunde hat ein spezielles Anliegen.

Der Kunde meint, sein Problem (Feature fehlt) zu verstehen und dessen Lösung zu kennen (Einbauen). Man bekommt Dokumentation und Code zu lesen und wird in die Komponenten des Systems eingeführt. Geht es dann an den Code, so wird man direkt auf große, schwere Klassen gelotzt, die irgendwie schwer zu warten sind, die jeder kennt und die jeder anfassen muss. Aber keiner traut sich. Das Problem liegt aber nicht dort wo der Kunde es vermutet, sondern an einer ganz anderen Stelle. Damit das Problem nachhaltig gelöst wird, ist Umdenken erforderlich.

Der Kunde hat also die Katze bereits getötet, nicht der Consultant. Er weiß nur noch nicht, dass sie tot ist.

Die Frage ist, wie die Therapie aussieht. Entlang der Metapher der Messiewohnung, unabhängig von der Katze: Es nützt dem Freund nichts, für ihn mal im Tine-Wittler Style so richtig aufzuräumen. Wie Jan ganz klar erkennt: Die unaufgeräumte Wohnung weist auf einen unaufgeräumten Geist hin. Hier ist eine Behandlung an der Wurzel nötig. Man muss den Messie die Wohnung selbst aufräumen lassen. Er muss sich von den einzelnen Objekten selbst trennen.

Die Entwickler müssen also selbst anfangen zu refaktorisieren und die Prinzipien zu erlernen. Sie müssen geschult werden, Tests zu schreiben und die SOLID Prinzipien zu reflektieren. Continuous Integration, - Deployment und -Delivery helfen hier weiter. Programmierern einfach einen OR/M, DI-Container oder Unittest drumrumzubasteln bringt ihnen nichts.

Hier finden sich übrigens ein Prinzip der humanistischen Psychologie wieder - Nur der Patient kann sich selbst heilen.

Es nützt nichts, einfach nur eine Methode mit 3000 Zeilen um eine zusätzliche Zeile für das fehlende Feature zu erweitern. Es nützt aber auch nichts, sofort die 3000 Zeilen zu refaktorisieren und 30 Klassen und 300 Tests anzulegen.

Es nützt nichts, eine Messiewohnung aufzuräumen. Es nützt aber eben auch nichts, eine tote Katze zu füttern.

Epilog: Was bleibt ist der Merksatz: Don't kill my cat. Und dann muss man ala Sixth Sense antworten: "Your cat has been dead the whole time".

Die Dritte Sprache

node<ItemType> it = new node<ItemType>(); 
it.item = se.ancestor<concept = EventHandler>.event : ActorEvent.actor

[tl;dr] : Die Vermischung natürlicher und fachbezogener Sprache verringert die Lesbarkeit. Weasel Words sind für diese Vermischung symptomatisch.

Geben Sie den Code oben mal einem Bekannten, der sich nicht mit Programmierung auskennt, und bitten Sie ihn, den Code vorzulesen. Hören Sie genau hin, was er liest. Sie werden hören, wie ulkig sich das anhört. Vor allem hat der Vorlesende hinterher keine Ahnung, was der Code machen könnte.

Der Code ist bereits durch die Datentypen etwas verwirrend. Aber ich frage mich: Wie kommt man, wenn man bei Verstand ist, darauf, eine Variable "it" zu nennen? Auf die Weasel Words möchte ich an dieser Stelle noch nicht eingehen. Klar, "it" - das soll irgendwie die Abkürzung für ItemType sein, aber das ist wohl auch nur bedingt aussagekräftig. Wenn, dann sollte es wohl eher "nit" sein. Immerhin haben wir ja die node-Funktion verwendet, also ist es wohl eher ein nodeItemType oder aber ItemTypeNode. Ganz unabhänig von der Sprache, in die dieser Code eingebettet ist - das ist doch Bullshit. Entschuldigen Sie den Ausdruck.

Deutsch und Englisch

Mein britischer Freund Andy Palmer fing während seiner Zeit in Deutschland an, Deutsch in einem Sprachkurs zu lernen. Leider kann fast jeder Deutsche Englisch. Das führte dazu, dass er bei seinen ersten Gehversuchen regelmäßig unterbrochen wurde. Bestellte er in gebrochenem Deutsch sein Mittagessen, so beantwortete die Bedienung oft in verhältnismäßig besserem Englisch seine Anfragen. Dies war sehr anstrengend für Andy. Er beschrieb es einmal so: Im Kopf läuft eine Schallplatte. Dabei läuft eine Nadel in einer Spur. Wenn man die Deutsch-Spur wählt, ist alles so lange gut, bis jemand auf Englisch antwortet. Dann macht die Nadel einen Sprung und landet wieder in der Englisch-Spur. Und so ein Spurwechsel ist anstrengend. Besonders wenn man sich zu einer Spur hingezogen fühlt. Für Andy ist es anstrengend, Deutsch zu sprechen. Umso leichter ist es, auf die englische Sprache zurückzufallen.

Für Manche kann dieser Spurwechsel ein Segen sein. Sonst würde so ein schmerzbefreiter Code wie der oben wohl nicht entstehen. Mir fällt das Wechseln zwischen den Spuren Deutsch und Englisch eigentlich sehr leicht, denoch glaube ich, dass genau dieser Spurwechsel mir Probleme mit dem o.g. Code verursacht. Ich glaube dass hier insgesamt 3 Sprachen vorhanden sind und dass der Grund, warum ich mit solchem Code Probleme habe, im Spurwechsel auf die dritte Sprache liegt. Ich finde hier Deutsch, Englisch und eine künstliche Konzeptsprache, die Weasel Words verwendet, um Muster und Technische Konzepte auszudrücken. Und ebendieser Spurwechsel zwischen Deutsch, Englisch und der dritten Spur bereitet mit Kopfschmerzen.

Eine Dritte Sprache

So wie die Begriffe Node, ItemType und EventHandler jongliert werden, sind sie wohl von ihrer eigentlichen sprachlichen Bedeutung unabhängig. Sie sind somit Fachbegriffe, die sich wie Anglizismen, Latinismen oder sonstige, künstliche Neologismen in den Sprachfluss eingliedern. Der Begriff ItemType ist also nicht als eine Übersetzung mit echter, sprachlicher Repräsentation zu verstehen und wird wohl auch nicht so wahrgenommen, sondern ist eher ein zusammengesetzter Fachbegriff, der als Fremdwort eine Einheit bildet. Bei Nutella fragt man sich ja auch nicht, was die Bedeutung dahinter ist, oder was das nun mit Schokolade zu tun hat. Element-Typ ergibt wenig Sinn und genauso fachspezifisch scheint ein Ereignisbehandler zu sein.

An sich sind Fachbegriffe sehr sinnvoll. Sie erlauben es, eine Sprache zu standardisieren und zu präzisieren. Oft lassen sich Ausdrücke vereinfachen. Ärzte haben ihre ganz eigene Sprache, auch Polizisten, Dreher und Schreinermeister, Drogenabhängige und Filmemacher. In der Psychologie begegnete mir vor kurzem der Begriff der "Ambiguitätstoleranz". Dies bedeutet die Fähigkeit eines Individuums, trotz ungewisser Resultate an der Erledigung einer Aufgabe festzuhalten. Dies ist unter anderem wichtig, wenn man Kreativität charakterisieren will. Der Begriff ist wesentlich prägnanter, als das, was er ausdrückt. Genau so sollte es sein.

Oft macht eine Standardisierung eine Sprache aber auch komplizierter. Eine Ampel heißt im Beamtensprech "Lichtzeichenanlage". Ein Blinker ist ein "Fahrtrichtungsanzeiger". Ein Polizist ist ein "Polizeivollzugsbeamter". Aus Rechtlicher Sicht sehr sinnvoll, so lässt sich im Bußgeldkatalog genau festhalten, dass man etwa 25 Euro zu zahlen hat, wenn man von einem Polizeivollzugsbeamten dabei beobachtet wird, wie man an der Lichtzeichenanlage ohne Setzen des Fahrtrichtungsanzeigers einfach so abbiegt. Je mehr Buchstaben man in ein Wort packt, desto mehr Information steckt drin. Durch die Verkettung von Begriffen (darin sind wir Deutschen sehr gut, vgl. Donaudampfschiffartsgesellschaftskapitänskajüte [1]) wird das Wort sehr beschreibend und aussagekräftig. Leider neigen Substantive dazu, durch ihre Anfangsbuchstaben abgekürzt zu werden. Dann wird aus dem Polizist ein PVB, aus der Ampel eine LZA und dem Blinker ein FRA. Für weitere Abkürzungen empfehle ich jetzt MFG von den Fantastischen Vier anzuhören. Dann ist die ganze Informationsfülle dahin und man muss den Code wieder entziffern. Von "Lesbarkeit" kann kaum die Rede sein, geschweigedenn von "Sprechbarkeit".

Der Kratzer in der Schallplatte

Aber wo liegt denn nun das sprachliche Problem mit den Fachtermini im Code? Sie erfordern (von mir) eben einen unangenehmen Spurwechsel.

Wenn jetzt ItemType als Floskel mit "it" (Sprich "IHHHH TEEEE") abgekürzt wird, dann ist IhTee immer noch im Deutschen "Eitemteip Modus". Der Sprechende verwendet die Begriffe wohl nicht als Sprachliche Elemente seiner natürlichen Sprache, also Englisch oder Deutsch, sondern als eingebettete Fachbegriffe. Dies scheinen die syntaktischen Elemente wie Operatoren, Semikola oder Klammern zu unterstützen. Ich als Englisch-Affines Gewohnheitstier lese aber ab dem Moment, wo jemand it schreibt nicht mehr IhTee oder EiTieh sondern eben it. "It". Ittttt. Also wie das it in "It is a beautiful day". Nicht EiTieh. [2]

Somit ist in dem Moment, indem ich den Code kognitiv verarbeite, die Sprach-Spur für technische Fachsprachen aktiv. Durch it, wird meine englische Sprachspur aktiv. Und diese durchmischt sich mit der Fach-Sprachspur. it.item ergibt keinen Sinn. ItemType.item ergäbe da schon mehr sinn, aber nicht, wenn man es auf Englisch, sondern nur wenn man es fachlich verarbeitet.

Ich plädiere für eine striktere sprachliche Trennung. Ich würde natürliche Sprache, ob Deutsch oder Englisch, bevorzugen. Um meinen Code zu analysieren, zu erklären und zu besprechen muss ich diese ohnehin auf Englisch oder Deutsch übersetzen. Dann könnte man Code auch Vorlesen, ohne dass andere denken, man hätte einen Schlaganfall.

Es ging bei dem gezeigten Code übrigens um einen Teil eines Backends für eine DSL. Diese konnte tatsächlich Begriffe wie Actor, Player oder RoomEnter/RoomExit verwenden. Es ging darum, einen Code auszulösen, wenn ein Spieler einen Raum betritt. Warum "RoomEnter" aber ein ActorEvent (SchauspielerEreignis?) ist und nicht eine "Bewegung" oder ein "Spielzug" weiß ich nicht. Vielleicht sollte ich mal richtig Englisch lernen.


[1] Das längste Deutsche Wort, das nicht zusammengesetzt ist, ist übrigens "Unkameradschaftlichkeit"

[2] Ein schöner Wortwitz dazu:
A router goes to see his doctor.
The doctor asks: "What appears to be the problem?"
And the router says: "It hurts when IP"

Kein Kommentar

/* ------------------------------------------------ */
/* ------------------------------------------------ */
/* ------------------------------------------------ */
//
// main function
//
int main(int argc, char **argv) {   
    // initialize gtk and set up gtkbuilder for UI import from xml
    gtk_init ( &argc, &argv );
}

// 150 Zeilen repetetiver Unfug

You don't say>

Kommentare

Kommentare im Code sind schlecht. Sie tragen Informationen, die in den funktionalen Code, und nicht als ignorierte Annotation zusätzlich zum Code stehen sollten. Grundsätzlich gilt:

Jeder Kommentar lässt sich durch eine Codeeinheit mit gleichem Namen ersetzen.

Wann Kommentare dennoch sinnvoll sind, bedarf zusätzlicher Diskussion.

Was ist ein Kommentar?

Zunächst sollte betrachtet werden, welche Arten von Kommentaren es gibt. Ich unterscheide Kommentare die...

Header und Metadaten

Besonders die Unterscheidung der ersten beiden Items bedarf einer Erklärung: Kommentare über funktionalen Code beinhalten ja so gesehen auch Metadaten, also beschreibende Daten über den Code. Ich meine jedoch auf der einen Seite Kommentare, die Code expliziter machen sollen, also ihn erklären, Abkürzungen und Akronyme erläutern oder Elemente der Problemdomäne beschreiben und auf der anderen Seite Metadaten wie Informationen über Lizenzrechtliches oder den Autor. Zwei Beispiele:

Metadaten aus der poplib.py

"""A POP3 client class.
Based on the J. Myers POP3 draft, Jan. 96
"""
# Author: David Ascher 
#         [heavily stealing from nntplib.py]
# Updated: Piers Lauder  [Jul '97]
# String method conversion and test jig improvements by ESR, February 2001.

Funktionsbeschreibung, aus dem i3 Window Manager

Con *ws = con_get_workspace(current->con);
// If no workspace could be found, this was a dock window.
if (!ws)
    continue;

Bei letzterem Beispiel greift der Kategorische Imperativ für Kommentare:

Ersetze jeden Kommentar durch eine Codeeinheit gleichen Namens.

Das könnte dann so aussehen:

Con* workspace = con_get_workspace(current->con);
if (no_ workspace_ could_ be_ found()) 
{
    this_is_a_docking_window();
}

Im ersten Fall wird das natürlich schwierig, da der Kommentar zwar syntaktisch verwendet wird, es sich aber nicht um einen echten Funktionskommentar handelt. Dies ist ein legitimes Mittel in der Open Source Welt, Lizenzen und Ähnliches festzulegen. Es ist jedoch zu beachten, dass es eigentlich nicht die Aufgabe jeder Datei ist, Lizenzen festzulegen.

Auskommentierter Code

Auskommentierter Code kann gelöscht werden. Sollte er später nochmal wichtig sein, kann man ihn durch die Versionskontrolle reanimieren. Ansonsten sind Compiler-Schalter effektiver, zum Beispiel #IF DEBUG #ENDIF. Diese lassen sich mit dem entsprechenden Build Target aktivieren.

Visuelle Wahrnehmung

Durch Syntaxhighlighting werden Kommentare farblich hervorgehoben. Dies kann den Effekt haben, dass sie besser oder schlechter sichtbar sind. Da ich keine Kommentare mag, stelle ich die Hervorhebung oft auf ein knalliges Orange ein, sodass ich auch ja keinen übersehe.

Emotionen

Oft vermitteln Kommentare Emotionen. Wenn beispielsweise in einer Codebase geflucht wird, weist dies auf Probleme beim Entwickeln oder eine angestrengte Atmosphäre im Team hin. Früher konnte man toll mit Google Code search nach Schimpfwörtern in allen möglichen Sourcecodes suchen. Flüche und Schimpfereien ermöglichen eine ganz eigene Metrik der Codequalität (und tragen oft zur Belustigung bei).

Umgang

Es gibt immer bessere Alternativen zu Kommentaren.

Header

Bei manchen Dateien muss man erstmal 3 Bildschirme lang an AGBs vorbeiscrollen, bis man den Quellcode sieht. Hier sollte man die Lizenz in ein zusätzliches Dokument packen und nicht direkt in die Quelldatei. Wenn man aber so sehr Angst um seinen Code hat, dass man jede Datei mit Lizenzgeschwafel verschandeln muss, kann man andere Wege gehen. Man kann diese beispielsweise automatisch in die Einfügen lassen mit Hilfe eines Build Scriptes. Der Code ist dann zur Entwicklungszeit frei von Mist, aber wenn er weitergegeben wird, enthält er die nötigen Informationen. Dann muss sich der Nächste damit rumärgern. Dies lässt sich über Buildscripte aller Art verwirklichen, Make/Rake/Fake/Psake - Gradle, (N)Ant oder python Skripte. Diese kann man in den Buildprozess mit einbeziehen, also beispielsweise nach dem Einchecken durch einen Post Commit Hook in Git.

Versionsinfos

Versions- und Autoreninformationen in solchen Headern sind schön und gut, aber eigentlich auch unnötig. Wofür hat man schließlich eine Versionskontrolle? Diese beinhaltet bereits den Namen des Commiters und das Datum, sowie die Version (bzw. Revision). Es spricht also auch hier alles dafür, die Kommentare zu entfernen und den Inhalt anderweitig bereitzustellen.

//TODO: Never.

Oft kommt als Argument für Kommentare, dass man ja TODO oder FIXME Nachrichten und Hinweise einfügen kann, um sich später daran zu erinnern, noch ein Feature oder Fehlerprüfungen einzubauen. Moderne IDEs sammeln diese TODOs und zeigen eine Übersicht an. Aus eigener Erfahrung kann ich aber sagen, dass ein TODO mehrere Monate besteht, bis er gelöscht wird. Das Feature wird nie eingebaut.

Für fehlende Features sollte man statt eines TODO-Kommentars lieber einen fehlschlagenden (roten) Test anlegen. Dieser beschreibt, dass ein Feature implementiert werden muss. Mit einem Branch und einer geeigneten Buildpipeline ist das einchecken fehlschlagender Tests auch unproblematisch. Tests sind wesentlich verbindlicher, sie zu reparieren ist Aufgabe des ganzen Teams.

Um den Lebenszyklus von TODOs (oder Kommentaren im Allgemeinen) nachzuvollziehen, kann man jedes mal, wenn man ein TODO findet, ein Tag hinterlassen. Ein Tag beinhaltet den Namen des Benutzers (Initialen reichen) und ein Datum. Sinnvoll ist auch den Grund des Besuchs der Datei hinzuzufügen, damit wird oft klar, dass der Besuch gar nichts mit dem Todo zu tun hatte. So entsteht eine Liste mit Datumsangaben, die der Kommentar überdauert hat, ohne dass die geforderte Veränderung umgesetzt wurde. Nach spätestens 3 Monaten Versionsgeschichte ist dann auch dem Letzen klar, dass das "TO DO", wohl doch nicht getan werden muss. Dann kann der Kommentar rausfliegen.

Man sieht: Tests vor Todos, VCS vor Dateiheader, Klare Funktionsnamen vor schlechten Hinweisen.

Was könnte ein Kommentar darstellen?

In seltenen Fällen bin ich gewillt Kommentare zu akzeptieren. Manchmal mache ich auch selbst Kommentare in den Code. Diese beinhalten aber weder Funktionsbeschreibungen noch Autoreninfos, sondern viel mehr verwende ich Kommentare für das, was die IDEs daraus macht. Farbliche Hervorhebung machen den Inhalt obsolet, stellen aber eine Wahrnehmungshilfe dar.

Kommentare - als Kommentare

Im richtigen Leben macht man Anmerkungen zu spontanen Einfällen oder um Freude oder Missgunst auszudrücken. So kann es auch im Code sein. Macht eine kleine Klasse genau das was sie soll, so kann man dem Autor eine Nachricht (ein Graffiti) hinterlassen - "Diese Klasse ist toll" oder "Wow, schnelle, schicke Implementierung". Wenn's mal wieder hochkocht kann man auch andere Sachen kommentieren: "Diese Implementierung ist so schmutzig wie deine Mudder". Natürlich immer den Namen und das Datum dazu packen und nicht sauer sein, wenn der Autor oder jemand anders den Kommentar löscht. Aber auch für "echte" Kommentare gilt: Sie haben nichts im Code zu suchen, sind nur temporär und stören meist. Für Ansichten und Meinungen würde sich ein Tweet oder eine Email an den Autoren mehr lohnen.

Links

Links sind hilfreich als Quellenangabe. Welches Pattern wurde verwendet und warum. Jedoch sollte man diese möglichst versteckt halten. Besser ist Links in eine eigene Datei zu packen und / oder sie bei der Commit-Message mit anzugeben.

Visuelle Marker

Kommentare können dann als visuelle Marker verwendet werden, also kann die Datei strukturiert werden und man kann visuelle Anhaltspunkte setzen. Das lässt sich mit einer Art Bookmarking Funktion vergleichen, sollte aber Temporär gehalten werden. Dateien sollten sowieso nicht mehr als eine Bildschirmseite füllen. Wenn ich während einer Refaktorisierung aber oft in einer Datei auf und ab springen muss, kann ein gut sichtbarer Kommentar mir beim schnellen Finden einer entsprechenden Stelle helfen. Auch visuelle Trennlinien sind denkbar, jedoch sollte allzu exzessiver Gebrauch von ASCII-Art vermieden werden.

Hilfreich und minimalistisch sind Kommentare in Tests einsetzbar. Unabhängig vom verwendeten Framework folgen alle Tests dem folgenden Schema:

  1. Zustand festlegen
  2. Zu testende Operation ausführen
  3. Endzustand verifizieren

Dieses wird in BDD-Tests als Given/When/Then, in klassischen Unit-Tests meist als AAA (Arrange/Act/Assert) besprochen. Tests sollten diese Schritte beinhalten. Ist die Reihenfolge verschoben oder fehlt ein Element, so ist dies ein Feedback an den Entwickler. Dieser sollte sich fragen: Warum fehlt das Element? Wo habe ich abgekürzt? Wieso ist dieses Objekt so schwer zu erzeugen? Kommentare lassen sich hier als Visuelle Marker einsetzen. Ich dekoriere meine Tests klassischer Weise so:

[Test]
public void ShouldCalculateTheSumOfNumbersUpToTheBoundaryUsingTheSmallGaussianSumAlgorithm() 
{
    // Arrange 
    int bound = 10;

    // Act
    var sum = SmallGauss(bound);

    // Assert
    Assert.That(sum, Is.EqualTo(55));
}

Jeder Block hat eine Zeile. Wenn es mehr sind, verlangt das nach Rechtfertigung. Wenn ein Teil fehlt frage ich mich warum. Im Team lässt sich durch so eine Syntax schnell die Qualität der Tests verbessern, wenn alle diese Struktur befolgen. Besonders für TDD-Anfänger ist dies eine Enorme Hilfestellung. Der Inhalt des Kommentar ist dabei nicht mal so ausschlaggebend. Diese könnten auch einfach 1,2,3 heißen. Dass aber der Arrange vor dem Act kommt, bedeutet, dass der Act immer in der Mitte steht. Wenn man eine Datei mit vielen Tests öffnet (und 3 Zeilen reichen oft nicht) und man will auf einen Blick identifizieren, welches das System under Test ist, wo die getestete Aktion erfolgt und wo der Urzustand festgelegt wurde, sind die Tests durch entsprechende farbliche Hervorhebung unentbehrlich. Aber eigentlich wird hier der Kommentar als Ersatz für ein fehlendes IDE Feature missbraucht (vgl. #region).

In einem Team in dem ich arbeitete hat diese Methode dabei geholfen, die Testqualität dauerhaft auf einem gleichbleibenden Niveau zu halten und Testanfängern TDD näherzubringen. Es hat dazu beigetragen, dass die AAA Struktur mantrenhaft vor jedem Test aufgesagt wurde, indem die AAA-Kommentare zuerst in jeder Test-Funktion eingefügt wurden, noch bevor eine Zeile Code geschrieben war. Auch hier sollten aber eigentlich, besonders in einem erfahrenen Team, die einzelnen AAA Elemente implizit klar sein. Heutzutage sehen meine Tests kommentarfrei so aus:

 Assert.That(SmallGauss(10), IsEqual.To(55))

Oder sogar

SmallGauss(10).Should().Be(55)

Weiterführende Literatur

Robert Mühsig hat zu diesem Thema einen Beitrag in seinem Blog: Captain Obvious Kommentare.

Auch Steven Schwenke hat einen Tipp, wie man mit Todos umgehen soll: how i deal with todo comments in code

Zusätzlich finden sich in seinem Artikel weitere Hinweise auf Kommentare zu Kommentaren von Ayende und Jeff Attwood.

Selbstverständlich findet sich auch ein Hinweis zu einer pragmatischen Kommentierweise im Clean Code Buch.

DDC - .NET Developer Conference

Die .NET Developer Conference (DDC) ist vorbei! Von Montag, 14.05 bis Dienstag 15.05.2012 fand die DDC in Nürnberg statt! Wie zu erwarten wurde daraus eine Mordsgaudi!

Danke Jungs (und Mädels)

Bedanken möchte ich mich bei den üblichen Verdächtigen, die diese Konferenz zu einem ausgezeichneten Erlebnis gemacht haben! Wir hatten wunderbare Diskussionen während und zwischen den Vorträgen und die Atmosphäre war entspannt und angenehm nerdig. Vielen Dank an: Alexander Zeitler David Tielke Florian Bender Golo Roden Jan Fellien Johannes Hoppe Kostja Klein Laurin Stoll Marcell Spiess Robert Eichenseer Roberto Bez Sergey Shishkin Steffen Forkmann Tilman Börner Tobias Richling und alle Teilnehmer!

Ich selbst habe zwei Vorträge gehalten, zum Thema Empathic Code und Weasel Words. Zusätzlich habe ich mit Golo Roden zusammen eine Einführung in verteilte Versionskontrollsysteme (DVCS) und Mercurial gegeben. Der eigentliche Vortragende musste leider absagen und ich hoffe Golo und ich waren ein ebenbürtiger Ersatz. Ich fand die Sessions sehr spassig und denke dass es vielen gefallen hat. Manche mussten stehen, haben aber durchgehalten. Besonders der Weasel Word Vortrag schlug große Wellen - später in den Sitzungen wurden immer mal wieder Sticheleien in Richtung Weasel Words abgegeben, wenn dann doch mal ein Manager, ein Worker oder ein Repository auftauchte. Das ist ein sehr gutes Zeichen! Ich hatte das Ziel, meine Freunde, Kollegen und Mitcoder auf Weasel Words aufmerksam zu machen und das hat damit ja wohl geklappt :)

Die Folien sind auf Github zu finden und werden auch bald im Download Pool der DDC vorhanden sein.

Tops und Flops

Ich habe einige Vorträge gesehen und war sehr beeindruckt, wie viel Fachwissen und Kompetenz vertreten war. Meine Highlights waren:

Tut mir leid liebe Kollegen, ich weiß, eure Hintern sind zum drauf Sitzen und nicht zum hineinkriechen, deswegen belasse ich es hier. Aber vorher möchte ich noch zwei sehr wichtige Nürnberger Watschn verteilen.

An die Orgas

Fast das selbe...

Liebes DDC Team, toll wars, schön habt ihr das gemacht. Lieber Golo, lieber Tilmann, es war mir eine Ehre an eurer Seite diese beiden tollen Tage erleben zu dürfen.

Toll:

Nicht so doll:

Verbesserungsvorschläge

How is my driving?

Zu guter Letzt:

How is my driving?

Bitte, gebt mir Feedback! Ich bin immer drauf angewiesen selbst zu hören wie es war. Ich freue mich wenn's positiv ist, aber besonders negative Kritik ist mir wichtig, denn nur an negativer Kritik kann ich mich verbessern. Aus diesem Grund versuche ich auch immer jedem direkt Kritik zu geben. Mir ist hier Offenheit und ein Nicht-Beleidigt-Sein wichtig. Wenn ihr also denkt: "Was für ein Quatsch, was will dieser irre", dann schreibt mir! Wie habt ihr den Vortrag wahrgenommen? Zu viele Schimpfworte? Zu hibbelig? Zu schnell? Das möchte ich von euch hören. Zögert nicht, mir eine Email zu schreiben an

euer name [at] spam punkt cessor punkt de

Spam ist nicht wörtlich gemeint, das ist lediglich meine Catch-All Adresse. Einfach euren Namen als Addressat ersetzen.

Auf Twitter bin ich @pro_cessor! Schreibt mir!

Update

More Python

Seit ca. 2 Jahren beschäftige ich mich mit Python (zwischenzeitlich mal intensiver, mal weniger intensiv) und mittlerweile fühle ich mich sicher genug, dass ich mir zutraue eine beliebige (Web)Anwendung in Python zu schreiben. Da ich eigentlich zuvor nur C# und Java programmiert hatte, stellt dies einen recht krasse Veränderung für mich dar.

Einen Großteil der Syntax habe ich verinnerlicht. Was nun noch fehlt sind zusätzliche Libraries, die mein Leben leichter machen könnten. Leider sind viele native Libraries in Python sehr hässlich. Manche Low-Level Operationen sind sperrig und nicht intuitiv. Mit dem Web zu arbeiten kann sehr "verbose" sein und die self. Syntax macht jedes noch so saubere OO-Design hässlich. Dennoch finde ich Python einen Genuss.

Es gibt mehrere Gründe, Python zu mögen. Allein die Philosophie hinter Python, "The Zen of Python", ist großartig.

Für alle aufstrebenden Einsteiger habe ich an dieser Stelle ein paar Links zusammengetragen, die beim Einstieg helfen könnten.

Grundlegende Tools

Libraries

Vorträge

Web

Ich habe leider nie mit Django gearbeitet, aber ich habe es vor. Django ist für Python wohl das, was ASP.NET MVC im .NET Bereich ist. Das Deployment geht sehr einfach in die Cloud auf Heroku.

Weiteres

Some common misconceptions

Seit geraumer Zeit erzähle ich den Leuten etwas über empathischen Code. Dieser baut auf die Konzepte von Clean Code auf. Bei den Vorträgen war ich immer wieder erstaunt, wie wenige Zuhörer Berührung mit den S.O.L.I.D. Prinzipien und wie viel weniger mit den zusätzlichen Prinzipien aus @unclebobmartin s Buch hatten. Glücklicher Weise bin ich nicht der Einzige dem dies auffällt.

Bevor diese Prinzipien jedoch überhaupt greifen können, sollten ein paar Dinge dargestellt werden, die nicht mal mit Klassen, Architektur und Design, sondern mit dem Code in jeder Zeile zu tun haben.

Kommentare

Kommentare beinhalten meist wichtige Meta-Informationen über den Code. Ich habe schon Kommentare gesehen, die die folgenden Informationen zu vermitteln versuchten:

Kommentare in Code sind wie politisches Graffiti. Es sind Schmierereien, oft nutzlos und hässlich, die nichts ändern und davon zeugen, dass der Autor keine bessere Möglichkeit fand, sich auszudrücken. Wenn eine Kommentar wichtig ist, dann ist der Inhalt meist auch wichtig genug, um vom Compiler nicht ignoriert zu werden. Deshalb lässt sich jeder Kommentar durch eine Funktion gleichen Namens ersetzen. Code sollte selbst expressiv sein. Die Expressivität sollte mit dem Code identisch sein, und nicht durch einen Kompiliervorgang verloren gehen.

Regions

Dermot Kilroy lehrte mich den folgenden Spruch: "Regions in Code zu verwenden ist wie den Klodeckel zuzumachen, ohne abzuspülen." Dieser stammt aber auch nicht von ihm direkt, ich habe aber leider vergessen, wer der Urheber ist.

@yardantan schreibt:

"[Ich] Finde #Regions eine feine Art inhaltslosen Code ausblenden zu können. [...]"

Ich finde, dass Code nicht inhaltslos sein sollte und in der Regel auch nie inhaltslos ist. Wenn Code keinen Inhalt, also keinen Nutzen hat, dann ist er nicht wichtig und man kann ihn löschen. Die genannten Elemente vereint: Sie behindern die Unterstützung durch den "Ausführer" im weitesten Sinne, also den Parser/Compiler, aber auch den Interpreter in dynamischen Sprachen. Sie behindern die Unterstützung von Refaktorisierungstools.

Hans-Peter Schelian unterstützte die Argumentation in Richtung Regions:

Tweet

Ich finde dass hier liest sich erst mal ganz gut gibt einen netten Überblick ohne den Code zu zeigen

Regions verstecken Code

Ich habe mir die Mühe gemacht, den Code etwas zu refaktorisieren. Hier ist eine Alternative, wie es ohne #region Element aussieht:

Methoden statt Regionen

Hier kann die Navigation mit den entsprechenden Shortcuts funktionieren. Zusätzlich lässt sich der Class-View in Visual Studio für die bessere Navigation verwenden. Die Typensicherheit, bzw. die Erhebung von Regions zu Methoden sorgt auch für ein besseres Tooling.

Codeeinheiten

Das am schwierigsten auszurottende Vorurteil ist, dass eine große Anzahl an Klassen schlechter verwendbar oder unwartbar sei. Das Gegenteil ist jedoch der Fall. Durch Ordner und Namespaces, sowie durch entsprechende "Finde"- oder "Springe zu"- Befehle lässt sich ein Wald an vielen Dateien und Klassen sehr gut beherrschen. Durch entsprechende Benennungsmuster lassen sich diese klar unterscheiden.

Außerdem werden dadurch mehrere Prinzipien implementiert:

Es lassen sich genügend Argumente finden, warum viele Klassen gut - und nicht wie fälschlicherweise angenommen anstrengender sind. Das letzte Argument für heute wiegt besonders schwer:

Zusätzlich zur Übersichtlichkeit und Expressivität bieten viele Klassen einen Nutzen in der Objektorientierung. Diese beschreibt, dass mittels Polymorphie, also der unterschiedlichen Anschauungs- und Darstellungsweise eines Objektes dessen Verhalten geändert werden kann. So können oft Methoden durch entsprechende Überladungen vereinfacht werden und man spart sich eine Menge prozedurale if-Statements:

void SendEmail(Email e) {
    if (e.IsValid) {
      e.Send()
    }
}

Warum nicht

void SendEmail(ValidEmail e) {
    e.Send()
}

Update

Schön wäre es, den obigen Code einmal zu finden. @andypalmer schrieb auf Facebook:

The Email bit isn't quite what we'd see in real life... we'd see

public void Send(string email)
‎{
    if(EmailHelper.IsValidEmail(email))
        EmailHelper.SendEmail(email);
}

Und damit hat er recht! Der heutige, befürwortete Stil erzeugt derartige Schindluder mit der Ausrede des SRP. Eine Email darf sich nicht selbst senden, da muss ein Helper (oder) ein Validator her. Es ist schade zu sehen, dass objektorientierung heute so missverstanden wird.

Johannes Hoppe schrieb als Kommentar dazu auf Facebook:

Andy you are wrong. There wont be an EmailHelper. There would be the following Snippet:

Und ergänzte den folgenden Code:

if (email != null && email != "" && Regex.IsMatch(email, 
    @"^(([\w-]+\.)+[\w-]+|([a-zA-Z]{1}|[\w-]{2,}))@"
    + @"((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\."
    + "([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\."
    + @"([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\."
    + "([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])){1}|"
    + @"([a-zA-Z]+[\w-]+\.)+[a-zA-Z]{2,4})$")) 
{
  // ...
}

Leider wahr. Es wäre schön, sich über Objektmodelle unterhalten zu können. Leider ist prozeduraler Code meist das Problem.