Samstag, 16. Januar 2010

Ja, wo programmiert er denn? [endlich-clean.net]

Das Jahr beginnt gleich wieder gut: Mit einer Menge Veranstaltungen. Und alle stehen Sie im Zeichen von Clean Code Developer (CCD). Das freut mich sehr, denn gedacht hätte ich das vor 12 Monaten nicht, als Stefan Lieser und ich die CCD Initiative gestartet haben. Irgendwie haben wir damit aber einen Nerv der Entwickler-Communities getroffen…

(Fast) Kein .NET-Event ist heute mehr ohne CCD-bezogenen Vortrag. Das ist toll! Denn damit ist der Beweis erbracht, dass Entwickler nicht nur an neuesten Technologien, sondern auch an Qualität interessiert sind. Es wäre schön, wenn wir uns dadurch als Branche ein wenig von der pessimistischen Sicht Nicolai Josuttis´ entfernten, der die Code-Qualität schon als tot proklamiert hat.

Und wo gibt es nun CCD live zu sehen? Wo können Sie mit Stefan und mir face2face diskutieren?

  • imageDen Anfang macht die OOP in München im Januar. Dort sind wir am 28.1. um 9h frisch und munter auf der Bühne – und verteilen auch eine ganze Reihe “CCD Devotionalien” ;-)
  • Im Februar folgt die VSone 2010 – ebenfalls in München, quasi unserem derzeitigen CCD-Hauptquartier. Stefan hält einen Vortrag über Domain Driven Design, das wir nahe an CCD sehen und macht einen TDD Workshop. Und ich spreche über Refactoring von Brownfield-Projekten und machen einen Workshop über… ebenfalls TDD, aber in Verbindung mit dem Thema Architektur. Beides liegt für mich dicht beieinander. “Ralf programmiert” heißt der Workshop, weil mir sehr daran gelegen ist, am Code zu demonstrieren, wie Konzepte und Praktiken zusammen kommen. Wir werden Software entwerfen, im Kleinen wie im Großen. Und wir werden eine Praktik wie TDD üben und die Brille des Flow-Patterns aufsetzen. Ich denke, das führt dann zu fruchtbaren Diskussionen und einigen Aha-Erlebnissen.
  • Im März ist lädt dann die dotnetpro zu 3 Tagen voller CCD ein: dem powerday, dem powerworkshop und dem powercoaching. Der powerday ist ein Präsentationstag, der einen Überblick über viele Aspekte von CCD geben soll; die besondere Herausforderung dabei an uns: Wir wollen auf der Bühne Brownfield-Code aus dem Publikum refaktorisieren. Ich bin gespannt, was die Teilnehmer uns da so einreichen. Während des powerworkshops wollen wir dann mit den Teilnehmern einen Ausschnitt an image Prinzipien und Praktiken von CCD einüben. Die Themen sind dann nicht so breit, es geht dafür in die Tiefe. Und das powercoaching ist eine Veranstaltung, bei der auch der Chef gern dabei sein kann; denn da geht es um den Review von konkretem Projektcode. Wir wollen uns mit Teams ihre Architektur und den Code-IST-Zustand ansehen. Das passiert ebenfalls auf einer (kleinen) Bühne und ist insofern ein Experiment. Experimentell ist natürlich nicht der Review – der funktioniert garantiert. Aber wir glauben, dass auch ansonsten Unbeteiligte aus so einem Review von Code Dritter etwas lernen können. Deshalb dürfen andere Teams, die ebenfalls zum Coaching kommen, das Coaching anderer verfolgen.
  • Mit diesen Veranstaltungen aber nicht genug CCD! Von Januar bis April laufen auch noch zwei CCD-Trainings – natürlich in München ;-) Bei der School of .NET sind da sogar noch 1-2 Plätze frei. Wer also kurzentschlossen noch mitmachen will, der ist herzlich eingeladen.

Wo ich im ersten Quartal programmiere, dürfte damit klar sein :-) Vielleicht haben Sie ja Lust, uns hier oder da zu begegnen. Dann schauen Sie doch vorbei und diskutieren mit uns über Ihre Erfahrungen mit CCD oder löchern uns mit Fragen. Wir freuen uns drauf.

Montag, 4. Januar 2010

Aspekttrennung im GUI

Mich wundert, dass es bisher noch niemand bemerkt zu haben scheint: Der WinForms-Designer (und auch der WPF-Designer) vermischt zwei Aspekte bei der GUI-Programmierung. Das sind die Aspekte Gestaltung und Funktionalität. Dass er das tut, finden wir natürlich alle irgendwie bequem. Doch mich beschleicht das Gefühl, dass hier zuviel des Guten getan wird.

Ein Beispiel ein kleines Formular zum Addieren zweier Zahlen:

image

Da steckt etwas Gestaltung drin –  Steuerelemente wollten ausgewählt und angeordnet werden – und Funktionalität – Ereignisbehandlungsroutinen wollten hinter die Steuerelemente gestellt werden.

Die Programmierung war ganz einfach: Steuerelemente auf das Formular ziehen (Gestaltung), Doppelklick auf ein Steuerelement, um einen Eventhandler zu schreiben (Funktionalität). So weit, so gut. Das möchte ich kaum anders haben.

Wenn ich genau hinschaue, stört mich aber das Ergebnis dieser einfachen Programmierung im Code. Das sieht nämlich so aus:

public partial class WinDoTheMath : Form

{

    public WinDoTheMath()

    {

        InitializeComponent();

    }

 

    private void button1_Click(object sender, EventArgs e)

    {…}

 

    private void textBox1_Validating(object sender, CancelEventArgs e)

    {…}

}

Ganz normal – aber subtil verstörend. Denn was mir hier fehlt, das ist eine Zuordnung der Ereignisbehandlungsroutinen. Die “stehen im Code nur so rum”. Ich muss mir anhand der im Methodennamen steckenden Hinweise zusammenreimen, wie/wann sie zum Einsatz kommen.

Das finde ich inzwischen irgendwie umständlich – oder anders ausgedrückt: Der Zwang zum Zusammenreimen erhöht für mich die Komplexität des Codes. Ich sehe einfach nicht die Abhängigkeiten bzw. Zusammenhänge. Die hat der Designer nämlich im code behind versteckt:

private void InitializeComponent()

{

    …

    //

    // textBox1

    //

    this.textBox1.Location = new System.Drawing.Point(12, 12);

    this.textBox1.Name = "textBox1";

    this.textBox1.Size = new System.Drawing.Size(55, 20);

    this.textBox1.TabIndex = 0;

    this.textBox1.Validating +=

           new System.ComponentModel.CancelEventHandler(this.textBox1_Validating);

    //

    // textBox2

    //

    this.textBox2.Location = new System.Drawing.Point(121, 12);

    this.textBox2.Name = "textBox2";

    this.textBox2.Size = new System.Drawing.Size(55, 20);

    this.textBox2.TabIndex = 1;

    this.textBox2.Validating +=

           new System.ComponentModel.CancelEventHandler(this.textBox1_Validating);

    //

    // button1

    //

    this.button1.Location = new System.Drawing.Point(202, 9);

    this.button1.Name = "button1";

    this.button1.Size = new System.Drawing.Size(75, 23);

    this.button1.TabIndex = 2;

    this.button1.Text = "Add";

    this.button1.UseVisualStyleBackColor = true;

    this.button1.Click += new System.EventHandler(this.button1_Click);

    …

Sehen Sie die Zusammenhänge? Die stecken in der jeweils letzten Zeile der Codeblöcke für die Steuerelemente. Dort wird der Eventhandler dem Control zugewiesen. Da geht es um Funktionalität. Und was steht davor? Das geht es um die Gestaltung.

Gestaltung und Funktionalität sind im code behind vermischt. Das ist gut gemeint vom Designer – aber ich finde das nicht mehr verständnisfördernd. Früher war das genial; heute fühle ich mich dadurch verwirrt. Liegt das am Alter? ;-) Nein, ich glaube, das liegt am durch Clean Code Developer geschärften Blick für Verständlichkeit und Abhängigkeiten.

Wo Zusammenhänge nicht sofort klar werden, da regt sich ein ungutes Gefühl bei mir. Und unklar sind sie, wenn ich nicht dort, wo ich Code lese – also im “foreground code” –, mich leicht darüber informieren kann, wer die beteiligten Parteien sind und wie sie zusammen hängen. Weder weiß ich dort, welche Steuerelemente es gibt, noch weiß ich, wie daran Ereignisbehandlungsroutinen geknüpft sind. Das finde ich unschön.

Ich werde daher in Zukunft nicht mehr einfach auf Steuerelementen doppelklicken, um mir Eventhandler generieren zu lassen! Stattdessen schreibe ich die von Hand. Dabei kann ich dann auch wählen, wie ich sie implementiere: ob als eigenständige Methode oder doch nur als Lambda Funktion:

public partial class WinDoTheMath : Form

{

    public WinDoTheMath()

    {

        InitializeComponent();

 

        this.textBox1.Validating += ValidateNumberEntered;

        this.textBox2.Validating += ValidateNumberEntered;

 

        this.button1.Click += (s, e) =>

              {

                  var sum = int.Parse(textBox1.Text) + int.Parse(textBox2.Text);

                  MessageBox.Show(string.Format("Sum: {0}", sum));

              };

    }

 

    private void ValidateNumberEntered(object sender, CancelEventArgs e)

    {

        int i;

        e.Cancel = !int.TryParse(((TextBox) sender).Text, out i);

 

        this.errorProvider1.SetError((Control)sender,

                                     e.Cancel ? "Input is not an integer!" : "");

    }

}

Jetzt habe ich alles auf einen Blick in der Codeansicht: die wirklich relevanten Steuerelemente mit ihrer Funktionalität.

Und ich habe die beiden Aspekte Gestaltung und Funktionalität sauber getrennt. Der Designer ist jetzt wirklich nur noch für die Gestaltung zuständig. Die schaue ich mir im Design View an – und der Code dafür liegt irgendwo verborgen, weil er mich für die Funktionalität, mit der ich sonst beschäftigt bin, nicht interessiert.

Das finde ich sauber. Wer noch?