Follow my new blog

Dienstag, 8. Juni 2010

Zwischenmahlzeit: Kurzvorträge zum Mittag in Karlsruhe, freier Eintritt

Wer mag sich zwischendurch inspirieren lassen? Das ist nämlich am Donnerstag 10. Juni 2010 in Karlsruhe möglich. Leicht verdaubare Happen für den Entwicklergeist statt Suppenkoma bieten nämlich acht Abschlussvorträge eines Rhetoriktrainings.

Von 13:00 Uhr bis ca. 14:30/15:00 Uhr halten die Absolventen des Trainings 10-15 minütige Kurzvorträge in der Albert-Nestler-Str. 10 im Raum Paris des Technologiezentrums bei der andrena objects ag. Hier ein Auszug aus der Themenliste:

  • Umstieg von .NET 3.5 auf .NET 4.0
  • Deliberation und Gruppenentscheidungen
  • Scrum
  • eclipse BIRT
  • Einblick in die Sprache R

Der Eintritt ist natürlich frei. Die Teilnehmer, meine Trainer-Kollegin Renate Klein und ich freuen uns über jeden, der seine (verlängerte) Mittagspause bei ein wenig geistiger Anregung mit uns verbringt. Es gibt Spannendes zu hören. Und die Teilnehmer profitieren vom unvoreingenommenen Feedback eines größeren Publikums.

Also, wie wärs?

image

Freitag, 4. Juni 2010

Intensiv, im Team, kostenlos – Das Clean Code Developer Praktikum

image  Clean Code Developer (CCD) werden, hat weniger mit Technologien zu tun, als vielmehr mit Gewohnheiten und Konzepten. CCD-Tugenden zu vermitteln stellt daher besondere Anforderungen an Trainer. Wie stellen die dann sicher, dass sie sie erfüllen?

Stefan Lieser und ich haben in den letzten 14 Monaten einige CCD-Trainings durchgeführt und fühlen uns durchaus wohl mit den Ergebnissen. Aber wir hätten die CCD-Initiative ja nicht begründet und auch noch die Reflexion auf den Werte-Schild gehoben, wenn wir selbst nicht danach leben wollten und würden.

Deshalb finden wir es an der Zeit, über unsere Trainings zu reflektieren. Das Feedback aus den bisherigen Trainings haben wir analysiert; daraus konnten wir wertvolle Hinweise ableiten. Aber einige Aspekte lassen sich schwer mit Fragebögen erheben. Wir meinen, dass sich Konzepte, Vorgehensweisen und Didaktik nochmal ganz anders analysieren und reflektieren lassen, wenn sie ganz bewusst von Anfang an Thema sind, wenn sozusagen ein Training in einer “Meta-Atmosphäre” stattfindet.

Für ein solches Training, bei dem wir nicht nur etwas weitergeben, sondern selbst viel lernen wollen, können wir ja aber natürlich kein Geld verlangen. Es wäre auch kein normales Training, sondern eher… tja, was denn? Wir haben es mal Praktikum genannt.

Der Deal

Im Juli bieten Stefan Lieser und ich ein Praktikum an, in dem wir 5 Tage mit 5 “Praktikanten” 1 Projekt nach CCD-Manier durcharbeiten wollen.

Dieses CCD-Praktikum ist kostenlos für die Teilnehmer.

Wir bringen unsere CCD-Erfahrung ein. Die Teilnehmer sollen also etwas lernen. Aber wir wollen das – wie gesagt – auf einem anderen Niveau als in einem üblichen CCD-Training tun. Statt in kleinen Schritten Inhalte zu vermitteln, wollen wir in großen Sprüngen voran. Wir wollen mehr anwenden, als erklären. Denn nur dann kommen wir wirklich weiter bei einigen CCD-Bausteinen.

Die Teilnehmer müssen daher schon ein gewisses Erfahrungsniveau in Bezug auf CCD und .NET-Entwicklung haben. Deshalb erlauben wir uns, ein Auswahlverfahren vorzuschalten. Interessierte bewerben sich durch Lösung von zwei Aufgaben.

Keine Angst, das sind keine schlimmen Aufgaben. Wer es ernst meint mit CCD, wird sie leicht lösen können. Hier ein Beispiel für eine Einreichung zu Aufgabe 1 von Steven Weiß.

Also, wie wär´s? Wer hat Lust und macht mit? Es gibt was zu lernen, es gibt was zu schaffen – und es gibt die Möglichkeit, uns mal so richtig die Meinung zu sagen ;-)

Hier mehr Infos zur Termin und Ort sowie Hinweise zur Bewerbung auf der Seite des Professional Developer College.

Wie sind sehr gespannt auf eure Beiträge!

Donnerstag, 3. Juni 2010

Wenn das Ziel der Weg ist – Über typische Verwechslungen [OOP 2010]

Erfolgreiche Typen haben immer klare Ziele. Ohne Ziele geht nix. “10% mehr  Umsatz im nächsten Jahr!” oder “Maximal 1 Bug Report pro Monat im Support” oder “Feature X bis zum 30.6.2010 realisieren” – das sind Ziele für echte Männer (und gern auch Frauen, wenn sie sich angesprochen fühlen). Die sind auch total SMART – ist zumindest in Bezug auf A=Attainable und R=Relevant zu hoffen.

Soweit der Stand der Ziel-Dinge. Den habe ich auch schon mal versucht zu verinnerlichen. Fällt mir aber für mich selbst oft nicht ganz leicht; SMARTe Ziele allerdings für andere zu fordern, ist etwas ganz anderes ;-) Doch darum geht es mir nicht. Ich bin vielmehr über etwas Grundsätzliches gestolpert.

Solche oder ähnliche Ziele sind wohl nötig “im Business” und auch sonstwo. Ok. Dazu kommen dann aber noch aus den Zielen abgeleitete Rahmenbedingungen. “Um das Ziel ‘10% mehr Umsatz im nächsten Jahr’ zu erreichen, bekommen Sie das Budget X.”, “Um maximal 1 Bug pro Monat zu erreichen, erhalten Sie die Ressourcen Y” usw. Ziele sind quasi nicht von Grenzen zu trennen, in denen sie erreicht werden müssen. Sie sind immer an irgendwelche Budgets gekoppelt (Geld, Zeit, Menschen, Maschinen, Material usw.).

Das hört sich auch plausibel an. Die Rahmenbedingungen stehen für den maximalen Preis, den man zahlen will, um ein Ziel zu erreichen. Und da immer viele Ziele zu erreichen sind, die zur Verfügung stehenden Ressourcen jedoch meist begrenzt sind, müssen sie in zielindividuelle Budgets partitioniert werden. Oder?

So plausibel sich diese Argumentation anhört, mir scheint sie ganz grundsätzlich an einem Missverständnis zu leiden. Oder sogar an mehreren.

Missverständnis #1: Das Ziel ist der Weg

Da ist zum einen das Missverständnis, Ziele seien irgendwie unbeweglich. Klar, das gibt es. In sehr künstlichen Umgebungen wie Sportschießständen sind Ziele meist unbeweglich. Ich habe selbst mehr als 10 Jahre Leistungssport auf solchen Schießständen getrieben und weiß, wovon ich rede. Selbst solche starren Ziele sind schwer zu treffen. Im Sportschießen bringt man deshalb einiges Material in Anschlag (sogar im doppelten Sinn). Da gibt es Schuhe, Jacken, Hosen, Handschuhe, Mützen, Riehmen um die Bewegungsfreiheit des Schützens einzuschränken – auf das er das Ziel leichter erreiche, äh, treffe. Trotzdem meinen Glückwunsch dem, der in diesem Rahmen Höchstleistungen vollbringt.

Allerdings, da wollen wir ehrlich sein, realitätsnah ist das Sportschießen nicht. Es ist eine tolle Disziplin, in der man eine Menge lernen kann – nur nicht den Umgang mit der Waffe in realen Situationen. Die sind nämlich insofern entscheidend anders, als dass man sich erstens selten auf sie so vorbereiten kann und zweitens – das ist der Knackpunkt – allermeistens mit Zielen aufwarten, die nicht stillhalten.

In der realen Welt sind Ziele immer das, was sich bewegt. Militär, Polizei und “außersportliche” Waffenfreunde wissen das. Deren Schießstände sehen deshalb auch anders aus. Dort bewegen sich die Ziele.

Die Kunst, Ziele im realen Leben zu treffen, besteht also darin, nicht zu erstarren, sich nicht einzuschnüren, sondern so beweglich wie das Ziel zu bleiben – und es trotzdem zu treffen. Managerseminare sollten deshalb vielleicht mal Völkerball ins Programm nehmen – da bewegen sich nämlich anders als bei Handball oder Fußball die Ziele. Oder wie wäre es mit einer Runde Paintball? Die würde nicht nur Erkenntnise zur Natur realer Ziele, sondern auch zur persönlichen Kondition bringen ;-) Doch das nur am Rande…

Also: Ziele “in der Natur” sind beweglich. Deshalb müssen Jäger ebenfalls beweglich sein. Menschen sind den Tieren insofern überlegen, als dass sie nicht nur körperlich, sondern auch geistig beweglich sind.

Umso verwunderlicher ist es, dass diese Beweglichkeit üblicherweise massiv eingeschränkt wird, wenn es um Ziele in Unternehmen geht. Nicht nur sind die merkwürdig unnatürlich fix; nein, auch die Beweglichkeit der Mitarbeiter, die sie treffen, äh, erreichen sollen, ist eingeschränkt.

Das fühlt sich für mich so an, als sei eigentlich der Weg, d.h. die Bewegung in den Randbedingungen oder gar die Randbedingung selbst das eigentliche Ziel. “Wichtig ist, dass Ihr das Budget einhaltet!” Besonders deutlich wird das Missverständnis, wenn Budgets ausgeschöpft werden müssen. Müssen! Denn sonst droht ja, dass das Budget im nächsten Jahr kleiner wird. Unverbrauchtes Budget ins nächste Jahr (oder zum nächsten Projekt) zu retten, ist kaum möglich.

Philosophisch-spirituell ist es hübsch, vom Weg als Ziel zu sprechen. In wirtschaftlichen Zusammenhängen fühlt sich das jedoch komisch an. Weg und Wegbegrenzungen dürfen nicht das Ziel sein. Wo das passiert, wird der Unternehmenszweck pervertiert und die Motivation der Mitarbeiter mit Füßen getreten. (Ok, ausgenommen die der Mitarbeiter, die dafür verantwortlich sind darauf zu achten, dass der Weg als Ziel eingehalten wird.)

Also: Ich plädiere für einen natürlichen Umgang mit Zielen. Wenn schon Ziele, dann solche, die sich bewegen dürfen. Wenn sich im Verlauf eines Jahres herausstellt, dass 10% Umsatzzuwachs nicht zu erreichen sind (aufgrund zu geringen Budgets oder sonstiger Faktoren), dann muss man den eigenen Anschlag nachführen. Die Objekte der Begierde sind da, wo sie sind – und nicht dort, wo man mit seinen Rahmenbedingungen hinzielt. Man muss sich suchen – dafür gibt es einen Sucher bzw. Kimme und Korn – und man muss sich ihnen nachführen, wenn sie sich bewegen. Das nennt man Zielen. Zielen ist eine Tätigkeit, kein Zustand.

Wer ein Ziel benennt, der muss das im Blick haben. Er muss seinen Jägern vertrauen, dass sie gut zielen können. Und er muss damit leben, dass sich die Ziele bewegen und die Jäger Freiheit brauchen, um ihnen folgen zu können. Und schließlich: Es kann die Zielverfehlung keine Sache der Ehre und der quasi persönlichen Enttäuschung sein. Zielverfehlung ist vielmehr der Normalfall in einer Welt hoch beweglicher oder im Nebel verborgener Ziele.

Zielverfehlung also mit noch engeren Rahmenbedingungen zu beantworten ist grob kontraproduktiv. Nicht Einschnürung hilft Jägern, sondern Befreiung, Mobilität, Autonomität.

Das haben Polizei und Militär schon lange begriffen. Die Helden sind heute nicht mehr Heere, sondern hochmobile, intelligente, autonome Einsatzkommandos – die vor Ort jeder unvorhergesehenen Bewegung ihrer Ziele folgen können.

Missverständnis #2: Das Ziel ist der Zweck

Dann gibt es noch ein zweites Missverständnis. Es werden nämlich oft Ziele für Zwecke gehalten. “Warum machen wir das alles hier, Leute? Um Geld zu verdienen! Und deshalb brauchen wir im nächsten Jahr 10% mehr Umsatz.” So wird ein Ziel schnell als Zweck geadelt.

Doch das halte ich für ein großes Missverständnis. Weder ist “10% mehr Umsatz” ein Zweck, noch ist “Geld verdienen” ein Zweck. Beides sind nur Mittel. Sie sind Mittel zu einem Zweck, zu etwas “Höherem”.

Da will ich jetzt nicht gleich Weltfrieden und Klimaziele beschwören – aber ein bisschen geht´s schon in die Richtung. Zweck ist, wofür etwas getan wird. Was ist der Antrieb hinter einer Unternehmung? Um dessentwillen werden Menschen zu Kunden. Der Zweck ist die Antwort auf die Frage: “Warum sollte sich irgendjemand für uns interessieren?” (Die Betonung liegt dabei auf “uns”, denn die “Identität der Firma” ist am Ende das einzige, was sich nicht austauschen lässt. Sie ist das, was sich nicht in ein fernes Land auslagern lässt, um es billiger herzustellen.) Er drückt aus, warum einer/eine Firma wirklich etwas tut.

Wenn der Zweck also “Geld verdienen” sein soll, dann ist die Frage, ob irgendjemand deshalb Kunde würde. Nein, ich glaube nicht. “Ach, du willst Geld verdienen? Klar, dann kaufe ich dein Produkt.” So funktioniert es nicht.

Aber: “Wir bauen die besten Autos der Welt”, ja, das ist ein Zweck. Oder “Unser Unternehmen gibt es, weil wir verstanden haben, was Ihnen bei der Ernährung am Arbeitsplatz fehlt.” Oder “Wir glauben daran, dass Software ohne Support auskommen kann.”

Das sind Zwecke, denn dazu können Sie sagen “Dafür kämpfe ich!”, “Dahinter stehe ich!”, “Das ist auch mein Anliegen!”, “Es gibt mir etwas, wenn ich mithelfen kann, diesen Zweck zu erreichen.”

“Viel Geld verdienen” oder “10% mehr Umsatz” oder “1 Bug pro Monat” sind keine Zwecke. Es sind nur Ziele. Deshalb sollte jede offene oder unterschwellige Überhöhung sofort angezeigt werden. Ziele dürfen nicht zu Zwecken umgemünzt werden, um ihnen mehr Gewicht zu verleihen.

Das bedeutet im Umkehrschluss: Wenn Ziele eben nur Ziele sind, dann können sie jederzeit hinterfragt werden im Sinne von Zwecken. Wer ein Ziel benennt, der muss Antwort darauf geben können, inwiefern es welchem Zweck diene. Welchem Unternehmenszweck dient “10% mehr Umsatz im nächsten Jahr”? Welchem Zweck dient “Nur 1 Bug pro Monat”?

Tja, bei solchem Nachfragen kann dann herauskommen, dass “10% mehr Umsatz” keinem Unternehmenszweck dient. Denn “Das beste Callcenter für Medizinprodukte!” als Zweck zu haben, bedeutet nicht unbedingt, “10% mehr Umsatz im nächsten Jahr” machen zu müssen. Es könnte sein, dass ein Ziel wie “Die Fluktuation der Mitarbeiter um 10% verringern” (bei gleichem Umsatz) dem Zweck viel dienlicher ist.

Fazit

Es ist so eine Sache mit den Zielen. Alle sollen welche haben – dafür gibt es ja auch Personalgespräche mit Zielfestlegungen. Aber der richtige Umgang mit ihnen, die passende Kultur zur Natur von Zielen, die sich in der realen Welt bewegen, ist nicht leicht zu finden. Und die Gefahr der Verwechslung von Ziel mit Zweck lauert überall und umso mehr, je verzweifelter man versucht, das Ziel zu rechtfertigen und zu erreichen.

imageWas tun? Mehr Völkerball spielen könnte helfen ;-) Oder mehr mit den Menschen umgehen, statt mit Human Resources. Denn wer letztlich Menschen, Maschinen, Geld und Zeit über einen Leisten schlägt, weil er in allem nur Ressourcen sieht, der vergisst, was am Ende des Tages der ultimative Zweck aller Unternehmen ist: den Menschen zu dienen. Egal, ob sie im Unternehmen sind oder draußen. Womit wir dann doch bei der Philosophie angelangt sind. Denn dass Menschen immer nur Zweck und nicht Mittel sein sollen, das sagte weiland Immanuel Kant.

Remote Communication mit Event-Based Components und Application Space

Wie Asynchronizität über “Zwischenstücke” in eine EBC-Architektur eingebaut werden kann, habe ich in einem früheren Blogposting beschrieben. Jetzt ist in der myCsharp.de Community die Frage aufgetaucht, wie denn eine verteilte Architektur mit EBCs realisiert werden könnte.  Die einfache Antwort: genauso ;-)

Damit meine ich, dass das, was zum Aspekt remote communication gehört, in eine EBC Standardkomponente verpackt werden sollte. Die Domänenlogik-Komponenten bekommen davon nichts mit. Hier als Beispiel eine simple Echo-Kommunikation: ein Client schickt eine Nachricht an einen Service, der sie (fast) unverändert wieder zurückschickt.

image

Die Kontrakte für die Komponenten sehen so aus:

public interface IClientEBC
{
    event Action<string> Out_RequestTextProcessing;

    void In_ProcessedText(string text);
}

public interface IServiceEBC
{
    void In_EchoText(string text);

    event Action<string> Out_Echo;
}

Und das sollte sich auch nicht ändern, nur weil sie nicht im selben Prozess laufen. Die Event- bzw. Nachrichtenorientierung der EBCs ist dafür eine gute Voraussetzung.

Wie die Implementationen für die Kontrakte aussieht, ist eigentlich uninteressant. Ein Blick auf die Verdrahtung lohnt allerdings. Hier der Host für beide Komponenten, solange sie im selben Prozess laufen:

namespace Servent
{
    class Program
    {
        static void Main(string[] args)
        {
            var service = new ServiceEBC();
            var client = new ClientEBC();

            client.Out_RequestTextProcessing += service.In_EchoText;
            service.Out_Echo += client.In_ProcessedText;

            Application.Run(client);
        }
    }
}

(Ich habe die Client-Komponente als WinForms-Formular ausgelegt; deshalb ruft der Host am Ende Application.Run() auf.)

Wie zu erwarten werden Instanzen beider Komponenten direkt zusammengesteckt. Der Client kommuniziert ohne Umwege mit dem Service.

Remoting zwischenstecken

Der Trick bei EBCs ist, dass Kommunikation über “Drähte” verläuft. Während Objekte normalerweise sozusagen zusammengeschweißt sind, gibt es bei EBCs immer eine Indirektion. Zwischen Client und Service sitzt ein Delegat.

Wie ich in einem früheren Blogposting gezeigt habe, ist das der Schlüssel zu großer Flexibilität. Denn wo sich Client und Service nicht wirklich “berühren”, ist es eigentlich egal, welche Distanz sie haben bzw. was zwischen ihnen sitzt.

Das nutze ich für´s Remoting nun aus. Zwischen Client und Service schiebe ich einfach zwei Standardkomponenten:

 

image

Die Client-Komponente kommuniziert nun nicht mehr direkt mit dem Service, sondern mit einem Proxy für ihn. Und der Service wird nicht mehr von der Client-Komponente angesprochen, sondern von einem Stub.

Ganz wichtig: Für Client und Service macht das keinen Unterschied! In WCF müssen Sie vorausschauen und für einen Service einen Service-Kontrakt definieren. Bei .NET Remoting müssen Sie einen Service durch Ableitung von MarshalByRefObject kennzeichnen. Immer, wenn Sie Funktionalität entfernt betreiben wollen, müssen Sie also speziellen Code dafür entwickeln.

Das ist hier nun anders. Der Code der Standardkomponente ist immer gleich. Sonst wäre es ja auch keine Standardkomponente ;-) Mit EBCs müssen Sie nie mehr Code für die Verteilung entwickeln. (Oder höchstens einmal für das Kommunikationsmedium Ihrer Wahl.)

Wie gesagt, Client und Service ändern sich nicht dadurch, dass Sie verteilt betrieben werden. Der Code jedoch, der die Komponenten verdrahtet, sieht anders aus. Er muss die Remoting-Infrastruktur starten und Client bzw. Service mit ihr verdrahten. Der Host für den Client sieht dann z.B. so aus:

namespace Client
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            using (var host = new RemotingHost(0)) // #1
            {
                var proxy = host.CreateProxy<string, string>(
                                     "localhost:9000/EchoService", // #2
                                     ProxyResponseHandlingModes.Sync); // #3
                var client = new ClientEBC();

                client.Out_RequestTextProcessing += proxy.In_Send;
                proxy.Out_Received += client.In_ProcessedText;

                Application.Run(client);
            } 
        }
    }
}

Der Komponenten-Host – eine Konsolenanwendung – startet die Remoting-Infrastruktur (#1) und erzeugt dann darüber einen Proxy für den Service statt des Service selbst. Wo der Service läuft, gibt eine URL an (#2). Wie die Kommunikation zwischen Proxy und Service läuft, kann dem Client egal sein. Hier kommen der Einfachheit halber aber TCP-Sockets zum Einsatz. Die Option ProxyResponseHandlingModes.Sync (#3) legt fest, dass Antworten im Synchronization Context des Client ankommen sollen; so gibt es kein Problem in WinForms-Anwendungen, denn durch das Remoting sind garantiert mehrere Threads im Spiel.

Hervorhebenswert: Der Proxy ist generisch. Er kann in jede Kommunikationsstrecke eingesetzt werden, die seinem Format folgt. Hier ist das eine bidirektionale Kommunikation auf zwei “Drähten”.

Ein Client-Host unterscheidet sich, wie Sie sehen, nur marginal von dem, der Client und Service gehostet hat. So soll es sein.

Und wie sieht es beim Service aus? Genauso simpel:

namespace Service
{
    class Program
    {
        static void Main(string[] args)
        {
            using(var host = new RemotingHost(9000)) // #1
            {
                host.CreateStub<string, string, ServiceEBC>(
                        "EchoService",
                        s => s.In_EchoText, 
                        (s, c) => s.Out_Echo += c);

                …
            } 
        }
    }
}

Der Service-Host startet dieselbe Remoting-Infrastruktur – allerdings unter Angabe eines TCP-Ports (#1). Die finden Sie beim Client in der Adresse des Service wieder (#2 im Listing davor). Der Client-Host übergibt an die Infrastruktur 0 als Port, weil ihm der Port egal ist. Er muss keinen Endpunkt definieren, weil er nicht explizit adressiert wird.

Dann erzeugt der Service-Host einen Stub für den Service. Das ist der Kommunikationsendpunkt, bei dem Nachrichten vom Proxy ankommen. Er leitet sie weiter an den eigentlichen Service. Für den Service ist der Stub der Client. Und wieder ist die Infrastruktur generisch und der eigentliche Service merkt nichts davon, dass er nun entfernt von Clients betrieben wird.

Achtung: Der Service wird hier nicht instanziert! Sein Typ und zwei Lambda Ausdrücke werden allerdings an die Factory-Methode übergeben. Die reicht sie weiter an eine ServiceFactory (s.u.). Das ermöglicht eine Erzeugung des Service für jede Nachricht wie beim Single-Call-Modus von .NET Remoting. Services zustandslos zu machen ist daher ein kleines Zugeständnis an die Verteilung. Allerdings ist das nicht zwangsläufig nötig; in diesem Fall ist es nur etwas einfacher, um die Diskussion um Remoting nicht noch mit Aspekten der asynchronen Verarbeitung zu belasten.

Das war´s. So einfach kann Remoting mit EBCs sein.

Fragt sich nur, wie es unter der Haube funktioniert :-) Ich habe es mit dem Xcoordination Application Space implementiert. Ihn habe ich in der dotnetpro beschrieben und in Grundzügen auch in meinem englischen Blog. An dieser Stelle halte ich deshalb meine Erklärungen knapp:

Host und Proxy der Remoting Infrastruktur

Der Remoting Host selbst ist einfach. Er startet eigentlich nur einen Application Space und dient als Factory für Proxy und Stub:

namespace ebc.patterns
{
    public class RemotingHost : IRemotingHost
    {
        private readonly IXcoAppSpace space;

        public RemotingHost(int tcpPort)
               : this(string.Format("tcp.port={0}", tcpPort)) { }
        public RemotingHost(string configString)
        {
            this.space = new XcoAppSpace(configString);
        }

        public void Dispose()
        {
            this.space.Dispose();
        }
    …

Ein Proxy ist schnell erzeugt:

public IRemotingProxy<TRequest, TResponse> CreateProxy<TRequest, TResponse>(
       string serviceAddress,
       ProxyResponseHandlingModes mode)
{
    var remoteStub = this.space.ConnectWorker<Port<Request<TRequest, TResponse>>>(serviceAddress);
    return new RemotingProxy<TRequest, TResponse>(remoteStub, mode);
}

Dazu nimmt der Remoting Host Kontakt mit einem generischen Service-Worker auf, dessen Adresse ihm der Client übergibt. Und der RemotingProxy übernimmt die Aufgabe, EBC-Nachrichten in AppSpace Nachrichten zu übersetzen:

namespace ebc.patterns
{
    public class RemotingProxy<TRequest, TResponse> : IRemotingProxy<TRequest, TResponse>
    {
        private readonly Port<Request<TRequest, TResponse>> remoteWorker;
        private readonly Port<TResponse> responses;

        private readonly Port<Exception> exceptions;
        private readonly SynchronizationContext ctx;

        internal RemotingProxy(Port<Request<TRequest, TResponse>> remoteWorker, ProxyResponseHandlingModes mode)
        {
            this.remoteWorker = remoteWorker;

            if (mode == ProxyResponseHandlingModes.Sync)
                this.ctx = SynchronizationContext.Current;

            // Antwort vom Service verarbeiten
            this.responses = new Port<TResponse>();
            Arbiter.Activate(
                new DispatcherQueue(),
                Arbiter.Receive(true, this.responses, msg => this.ProcessMessageInSyncContext(msg, this.Out_Received))
                );

            // Exceptions vom Service verarbeiten
            this.exceptions = new Port<Exception>();
            Arbiter.Activate(
                new DispatcherQueue(),
                Arbiter.Receive(true, this.exceptions, ex => this.ProcessMessageInSyncContext(ex, this.Out_Exception))
                );

            this.Out_Exception += ex => { };
        }

        void ProcessMessageInSyncContext<T>(T msg, Action<T> messageHandler)
        {
            if (this.ctx != null)
                this.ctx.Send(x => messageHandler(msg), null);
            else
                messageHandler(msg);
        }

        public void In_Send(TRequest message)
        {
            var c = new Causality("ex", this.exceptions);
            Dispatcher.AddCausality(c);
            {
                var req = new Request<TRequest, TResponse> {
                                  Data = message,
                                  Response = responses};
                this.remoteWorker.Post(req);
            }
            Dispatcher.RemoveCausality(c);
        }

        public event Action<TResponse> Out_Received;
        public event Action<Exception> Out_Exception;
    }
}

Außerdem übernimmt der Proxy auch die Exception-Verarbeitung. Das habe ich bisher der Einfachheit unterschlagen. Wenn Exceptions vom Service kommen, dann leitet der Proxy sie auf einem speziellen Output-Pin weiter. Damit ist die Behandlung gleich, egal ob der Client Antworten vom Service in seinem Synchronization Context empfangen will oder nicht.

image

Stub der Remoting Infrastruktur

Auf der Service-Seite sieht es etwas kniffliger aus. Die ist nämlich grundsätzlich multi-threaded. Derselbe Stub wird für viele Anfragen und Antworten benutzt. Daher müssen Antworten vom Service, der nichts von solchen Feinheiten weiß, mit Anfragen korreliert werden. Nur so können sie an den, der die Anfrage geschickt hat, zurückgesandt werden.  Deshalb ist der Stub nicht fest verdrahtet mit einer Service-Instanz (was allerdings möglich wäre). Das obige Bild von Stub und Service ist also eine Vereinfachung. In Wirklichkeit sind die Verhältnisse so:

image

Das ändert zum Glück nichts daran, dass der Service nichts von seinem Glück wissen muss, remote betrieben zu werden.

Wie funktioniert das Ganze nun? Also…

1. Eine Anfrage kommt vom RemotingProxy über ein Transportmedium im RemotingStub beim StubWorker an. Der StubWorker ist ein AppSpace Worker, der die Übersetzung von CCR Port-Kommunikation auf EBC Events übernimmt. Da er asynchron arbeitet, braucht er eine Möglichkeit, Antworten Anfragen zuzuordnen. Deshalb enhält sein Nachrichtenaustausch mit einer angeschlossenen EBC KorrelationsIDs.

namespace ebc.patterns
{
    internal class StubWorker<TRequest, TResponse>
                   : Port<Request<TRequest, TResponse>>
    {
        private readonly Dictionary<Guid, IPort> responsePorts = new Dictionary<Guid, IPort>();

        [XcoConcurrent]
        public void ProcessRequest(Request<TRequest, TResponse> req)
        {
            var msg = new CorrelatableMessage<TRequest>(req.Data);
            lock (this.responsePorts)
            {
                this.responsePorts.Add(msg.CorrelationId, req.Response);
            }
            this.Out_Received(msg);
        }

        public void In_Reply(CorrelatableMessage<TResponse> msg)
        {
            IPort response;
            lock (this.responsePorts)
            {
                response = this.responsePorts[msg.CorrelationId];
                this.responsePorts.Remove(msg.CorrelationId);
            }
            response.PostUnknownType(msg.Data);
        }

        public event Action<CorrelatableMessage<TRequest>> Out_Received;
    }
}

2. Der Kommunikationspartner des Workers kann wg. der KorrelationsIDs nicht der Service sein. Der hat von solcherlei Dingen keine Ahnung. Stattdessen reicht der Worker die Anfrage weiter an die ServiceFactory. Die erzeugt dafür eine neue Service-Instanz – und schaltet ihr eine Standardkomponente vor, die Nachrichten mit KorrelationsID in solche ohne umwandeln kann (und umgekehrt).

namespace ebc.patterns
{
    internal class ServiceFactory<TRequest, TResponse, TService>
                   : IServiceFactory<TRequest, TResponse>
        where TService : new()
    {
        private readonly Func<TService, Action<TRequest>> inputPin;
        private readonly Action<TService, Action<TResponse>> connectOutputPin;

        public ServiceFactory(
                Func<TService, Action<TRequest>> inputPin,
                Action<TService, Action<TResponse>> connectOutputPin
            )
        {
            this.inputPin = inputPin;
            this.connectOutputPin = connectOutputPin;
        }

        public void In_Request(CorrelatableMessage<TRequest> request)
        {
            var corr = new SyncCorrelator<TRequest, TResponse>();
            var service = new TService();

            corr.Out_Received += this.inputPin(service);
            this.connectOutputPin(service, corr.In_Correlate);

            corr.Out_Reply += r => this.Out_Response(r);

            corr.In_DeCorrelate(request);
        }

        public event Action<CorrelatableMessage<TResponse>> Out_Response;
    }
}

Die ServiceFactory bastelt also dynamisch für jede Anfrage einen EBC-Platineninhalt zusammen, den sie mit ihren eigenen Pins verbindet.

Das ist kein Hexenwerk, aber doch ein bisschen umständlich. Zum Glück muss es nur einmal implementiert werden und ist dann für alle Kommunikationen gleich. Einfacher wäre es allerdings, der Service wäre darauf ausgelegt, asynchron und thread-safe zu arbeiten. Dann käme er selbst mit KorrelationsIDs zurecht und müsste nicht immer neu erzeugt werden. Dann wäre das Bild tatsächlich so einfach wie oben: Stub spricht mit Service. Wie Sie sehen, geht´s aber auch so, ohne Vorüberlegungen. Das ist das schöne an EBCs.

Im folgenden Bild stelle ich die beiden alternativen mal nebeneinander:

image

Der Quellcode, den Sie in einem Mercurial Google Projekt hier finden, spiegel das allerdings nicht wider. Er entspricht noch dem Bild, bei dem der RemotingStub die ServiceFactory enthält. Sauberer finde ich allerdings diese letzte abgebildete Variante. Sie entzerrt die Verantwortlichkeiten. Der RemotingStub ist nur für die Kommunikation zuständig – auch wenn das bedeutet, dass er Nachrichten mit KorrelationsIDs erzeugt/konsumiert. Darauf kann sich die bei Bedarf einstellen: Ist der Service nicht damit vertraut, muss er pro Nachricht neu instanziert werden. Dazu verdrahten sie ihn passend auf einer eigenen Platine.

Fazit

Client und Service müssen nicht speziell auf eine Verteilung vorbereitet werden. Und Sie müssen für eine Verteilung auch nichts extra programmieren, keine Service- oder Datenkontrakte sind nötig. Die Remoting-Infrastruktur kann generisch sein. Sie stecken sich also zusammen, was Sie brauchen.

Das bedeutet nicht, dass Sie keinen Gedanken verschwenden sollen, ob Services lokal oder entfernt betrieben werden. Die grundsätzliche Asynchronizität (oder auch mal Unverfügbarkeit ;-) eines entfernten Dienstes können seine Implementation beeinflussen. An der grundsätzlichen Einfachheit des Zusammensteckens ändert das jedoch nichts. Mal stecken Sie nur weniger, mal mehr zusammen.

Und nun: Basteln Sie schön :-) Arbeiten Sie mit der Remoting-Infrastruktur dieses Beispiels oder bauen Sie eine eigene auf Basis von .NET Remoting oder WCF oder was Sie wollen. Bei EBCs ist das noch erlaubt, weil sie so neu sind :-)

Dienstag, 1. Juni 2010

Die Ubiquitous Language konsequent codieren [OOP 2010]

Das war mir doch ein Experiment wert: Wie würden es Entwickler aufnehmen, wenn quasi alle Parameter von Methoden (zumindest in den Kontrakten von Komponenten) nicht primitiv sein sollen? Auf dem Coding Dojo in München habe ich es ausprobiert.

Das Beispielszenario dort war eine Rechtschreibprüfungsanwendung. In der gibt es dann irgendwo eine Funktion WortKorrekt() o.ä. Deren Signatur würde üblicherweise so aussehen:

bool WortKorrekt(string wort)

Darin sind zwei primitive Typen zu finden: bool und string.

Ich bin nun der Meinung, dass wir uns anstrengen sollten, solche Typen (zumindest in den Kontrakten von Komponenten) zu vermeiden. Statt unspezifischer primitiver Typen sollten wir spezifische Typen passend zur Problemdomäne definieren.

Codegrundlage Ubiquitous Language

Über die Problemdomäne sprechen wir unter uns und mit dem Kunden in der Ubiquitous Language (UL).  Es ist deshalb wichtig, sie in unserem Code wiederzufinden. Sonst müssen wir ständig Aufwand treiben, um unsere Rede in Code (und wieder zurück) zu übersetzen. Code würde weniger verständlich. Und wir wären unsicherer, ob wir unseren Code geeignet strukturiert haben, denn die Begriffe der UL sollten darin repräsentiert werden.

Damit wir uns der UL bewusst werden, habe ich im Dojo mit den Teilnehmern eine Concept Map der UL für die Domäne “Rechtschreibprüfung” erarbeitet:

image

Die sieht ein bisschen wüst aus, vor allem, weil man meine Schrift schon nach wenigen Minuten unleserlich wird ;-) Doch mir gehts hier nicht um Einzelheiten, sondern einfach mal eine Impression.

Die Concept Map enthält für jeden Begriff der Domänensprache einen “Kuller”. Unterschieden wird dabei nicht zwischen Daten und Diensten, Verben und Substantiven. Was wichtig ist, wird in einen Kreis gesetzt. Und dann werden die Begriffe verbunden mit qualifizierten Beziehungen. Ein “Wörterbuch” (Begriff) ist z.B. “abgefasst in” (Beziehung) einer “Sprache” (Begriff).

Der Vorteil einer Concept Map (z.B. statt eines Klassendiagramms) in einem frühen Stadium der Planung ist seine Informalität. Es gibt nur wenige Regeln zu beachten. Sie können Ihren Gedanken freien Lauf lassen. Ziel ist Vollständigkeit in Bezug auf Begriffe/Konzepte und Beziehungen auf einem hohen Abstraktionsniveau. Concept Maps sind Landkarten des Begriffsterrains der Problemdomäne.

Worauf ich nun hinaus will: der Concept Map können Sie die grundlegenden Funktionseinheiten und Daten der Problemdomäne entnehmen. Sie dient mithin der Hinführung zur Implementierung. Die Konzepte “Prüfer” und “Parser” in der Concept Map der Rechtschreibkontrolle sollten also z.B. als Services implementiert werden. (Nein, ich meine nicht SOA-Services, sondern benutze den Begriff “Service” für dienstleistungsorientierte Funktionseinheiten im Gegensatz zu solchen, die eher Daten halten.)

“Wörterbuch” hingegen hört sich eher wie eine Datenstruktur oder zumindest eine Entität an.

Soweit so normal. Sie wären auf diese Konzepte und ihre spätere Implementierung als Klassen vielleicht auf anderem Weg gekommen; identifiziert hätten Sie sie jedoch allemal.

Jetzt aber zu Prüftext, Prüfwort und Fehlerwort. Das sind ebenfalls Begriffe der Domänensprache. Doch wie übersetzen Sie die in Code? Das sind keine Services, keine Entitäten, nicht mal “echte” Datenstrukturen. Der Prüftext ist eher nur ein Text in einer bestimmten Situation. Dito das Prüfwort und das Fehlerwort. Prüfwort und Fehlerwort mögen sogar dieselben Texte sein, einmal vor der Prüfung und einmal hinterher.

Da liegt es doch nahe, diese Begriffe in string-Parameter/Felder zu übersetzen, oder? Die obige Funktion tut das exemplarisch und sieht normal aus, oder? Immerhin haben diese Begriffe keine weiteren Eigenschaften, sind nur “im Fluss” zwischen Services zu finden und ihre Daten müssen auch nicht persistiert werden. Einer so simplen Übersetzung steht daher nichts im Wege.

Primitiven der Ubiquitous Language codieren

Die klassische OOA/OOD kennt natürlich die Repräsentation von Domänenbegriffen als Klassen. Aus einem “Kunden” wird die class Customer, aus einem “Termin” die class Appointment, aus einem Auftragsstatus ein enum OrderState usw. Begriffe, die offensichtliche Eigenschaften haben oder zusammengesetzt sind und Daten repräsentieren, werden in class oder struct übersetzt.

Eine Rechnung besteht aus einer Rechnungsnummer, einem Rechnungsdatum, einem Kunden und vielem mehr. Die Übersetzung sieht dafür meist so aus:

class Invoice
{
    public string InvoiceNumber { get; set; }
    public DateTime InvoiceDate { get; set; }
    public Customer Customer { get; set; }
    …
}

Rechnung und Kunde haben eigene Datentypen bekommen, alle anderen Informationen sind als primitiv eingestuft und mit Standarddatentypen definiert.

Dem möchte ich nun entgegenhalten, auch Primitiven der Domänensprache durch eigene Datentypen zu repräsentieren. Ja, genau: Auch wenn ein Begriff nur für eine ganze Zahl oder eine Zeichenkette steht, sollten Sie ihm eine Klasse (oder eine Struktur) spendieren. Die Implementierung der Rechnung würde dann z.B. so aussehen:

class Invoice
{
    public InvoiceNumber Number { get; set; }
    public InvoiceDate CreatedAt { get; set; }
    public Customer Customer { get; set; }
    …
}

Oder die Prüfroutine der Rechtschreibkontrolle würde so aussehen:

bool WortKorrekt(PrüfWort wort)

Warum das? Ist nicht bool WortKorrekt(string wort) genauso gut zu lesen, genauso aussagekräftig wie bool WortKorrekt(PrüfWort wort)?

Landläufig betrachtet liegen beide in puncto Verständlichkeit nahe beieinander. Doch ich behaupte, dass Code, der weniger mit primitiven oder allgemeinen Typen des .NET Framework arbeitet und stattdessen konkrete Typen der UL benutzt, typsicherer ist und semantisch weniger Zweifel lässt.

Am Ort der Definition mag das weniger sichtbar sein als am Ort der Nutzung:

if (prüfer.WortKorrekt(new PrüfWort(…)))

oder

var inv = new Invoice(InvoiceNumber.Create(), InvoiceDate.Today(), …);

lassen weniger Zweifel, ob zusammenpasst, was zusammenpassen soll.

Einer Zeichenkette “Daten” können Sie nicht ansehen, was sie bedeutet. Es ist einfach nur eine Zeichenkette. Aber new PrüfWort(“Daten”) ist ganz eindeutig etwas anderes als new Dateiname(“Daten”). Ebenso ist new InvoiceDate(“2010-06-01”) (der erste Tag im Monat Juni) etwas anderes als new InvoiceNumber(“2010-06-01”) (die erste Rechnung im Monat Juni).

Die übliche Objektorientierung richtet ihr Augenmerk auf Objekte, d.h. “Dinger mit Eigenschaften”. Ich möchte Sie motivieren, genauer hinzusehen. Zoomen Sie näher heran und sehen Sie die Eigenschaft als letztlich nichts anderes als die Objekte. Die Welt ist rekursiv. Sie besteht aus “Objekten”, die aus “Objekten” bestehen, die aus “Objekten” bestehen usw. Und auf jeder Ebene kann es Begriffe der Ubiquitous Language geben.

Im Beispiel besteht ein Prüftext aus Prüfworten. Das versteht ein Entwickler wie auch der Kunde. Wird das bei der Codierung nur in die Zerlegung einer Zeichenkette in Zeichenketten übersetzt, dann entsteht eine Diskrepanz zwischen Sprache und Code. Der Grundstein für Missverständnisse ist gelegt.

So sollte in der Rechtschreibkontrolle also die Service-Funktionseinheit Parser besser wie folgt definieren:

class Parser
{
    IEnumerable<Prüfwort> ZerlegeText(Prüftext text) { … }
}

mit

class Prüftext
{
    public string Text;
}

class Prüfwort
{
    public string Wort;
}

(Dass ich hier der Klasse Prüftext keine Methode gebe, über die man an ihre Worte herankommt, möchte ich undiskutiert lassen. Das ist ein Thema für einen anderen Blogartikel.)

Zusammenfassung

Seien Sie rigoros bei der Implementierung. Nehmen Sie die Ubiquitous Language Ihrer Problemdomäne ernst. Repräsentieren Sie alle Begriffe durch “Kontrakte” (Interface/Klasse, Struktur, Methodensignatur). Primitive Typen des .NET Framework sollten “im API” von Komponenten auf das Nötigste beschränkt sein. Stattdessen übersetzen Sie selbst primitive Konzepte der Domäne in eigene Typen.

Sie machen damit ihren Code leichter lesbar und auch leichter veränderbar. Denn wenn heute ein Prüfwort womöglich nur eine Zeichenkette ist, dann könnte es morgen eine Zeichenkette mit einer Position in einem Text sein.

class Prüfwort
{
    public string Wort;
    public Textposition Position;
}

Und übermorgen ist es eine Zeichenkette mit einer Position in einer Sprache.

class Prüfwort
{
    public string Wort;
    public Textposition Position;
    public Wörterbuchsprache Sprache;
}

Machen Sie Ihren Code an jeder Stelle so präzise und domänenorientiert wie möglich.

Montag, 31. Mai 2010

Gezieltes Coding Dojo

Dass das Coding Dojo am 26.5.2010 kein Coding Dojo war, darüber sind Ilker und ich uns durchaus einig. Der Rahmen war zwar der des üblichen Münchner Dojos – der Inhalt wich dann jedoch stark davon ab. Ilker hat diese Abweichung jetzt nochmal begründet und ich habe auch schon innerhalb dieser bezweckten Abweichung reflektiert. Was bleibt da noch zu sagen?

Messlatte #1: Die offizielle Zieldefinition

image Mir geht der Kommentar von Steffen Forkmann nicht recht aus dem Kopf. Ist da wirklich etwas zu kurz gekommen beim Dojo? Wenn etwas zu kurz kommt, dann weicht etwas vom Ziel ab. Was aber ist das Ziel eines (oder des Münchner) Coding Dojos?

In einem früheren Posting von Ilker ist zu lesen, das Ziel eines Coding Dojos sei…

“[d]ie erfolgreiche Vermittlung von nutzbaren Lerneffekten – für jeden Teilnehmer. Er sagte dass ein Dojo keine feste, durchgeplante Veranstaltung mit fixem Programm oder Paradigma sei, sondern dass das Dojo primär die Teilnehmer und den Lerngedanken im Fokus hat.”

Wenn ich das in Anschlag bringe, dann bin ich ziemlich sicher, dass auch das letzte Coding Dojo sein Ziel erreicht hat. Niemand sollte zu kurz gekommen sein. Denn einen “nutzbaren Lerneffekt” hat es für jeden gegeben. (Wer keinen hatte, melde sich bitte bei mir. Dann bessere ich nach.)

Und da es keine “feste, durchgeplante Veranstaltung mit fixem Programm oder Paradigma” ist, sollte auch meine anders als übliche Nutzung der Dojo-Zeit dojokonform gewesen sein.

Allerdings: Wie steht es mit den “Teilnehmer[n] und de[m] Lerngedanken”? Mein Eindruck war, dass die Teilnehmer nicht nur Empfänger waren, sondern stets mitgestaltet haben. Anders als sonst, aber immer noch aktiv. Sehr aktiv sogar.

Fazit: Gem. der öffentlichen Definition des Münchner Coding Dojos ist alles im grünen Bereich gewesen. Anders, ungewohnt, aber zielführend. Ilker hat sich “nichts zu Schulden kommen lassen”. Als “Salonier” des Community Lernens hat er seine Aufgabe erfüllt. Merci, Ilker!

Messlatte #2: Selbstgebastelt

Soweit die offizielle Definition von Coding Dojo. Ich möchte jedoch die Gelegenheit nicht verstreichen lassen, mir auch selbst über die Ziele eines Coding Dojos Gedanken zu machen. Was gehört aus meiner Sicht dazu?

Zunächst einmal zum Begriff bzw. dem Bild des Dojo: Steffen Forkmann (und andere) scheinen enttäuscht gewesen zu sein, dass im letzten Dojo soviel “Lehrereinsatz” war. Das ist allerdings – zumindest im Hinblick auf das klassische Dojo – ein Missverständnis. Ein klassische Dojo ist ein Ort des Lernens des rechten Pfads, der auch von Religion geprägt ist. Im Dojo geht es also klassisch um einen Kanon vermittelt durch eine Lehrer/Meister-Schüler/Lehrling-Hierarchie. Der Gedanke einer gleichberechtigten Community in Bezug auf die Lerninhalte ist dem klassischen Dojo fremd.

Wenn nun die Softwaregemeinde den Begriff Dojo für sich entdeckt, dann halte ich es für vermessen (oder zumindest missverständlich) ihn ohne diese klassische Wurzel zu denken. Ein Dojo nur als Dojo zu akzeptieren, wenn es keinen Lehrer gibt, täte also besser, die Veranstaltung anders zu nennen.

Das soll nicht bedeuten, dass in einem Coding Dojo alles so laufen soll wie in einem Kendo Dojo im Japan des 17. Jahrhunderts. Modernisierung im Geiste westlicher Gleichberechtigung und Individualität ist natürlich völlig ok. Achtsamkeit im Umgang mit einem Traditionsbegriff scheint mir jedoch angebracht. Insofern bin ich der festen Überzeugung, dass in einem Dojo auch mal eine Hierarchie auftreten darf: einer weiß was, die anderen wollen es von ihm lernen.

Überwachung der Zielerreichung: Ob mit der ohne Lehrer – in Ilkers Definition ist das ja auch offen gelassen –, ein Ziel ist für ein Dojo wie für jede Veranstaltung nötig. Laut Ilker ist das “nutzbare Lerneffekte”; im Dojo soll also irgendetwas gelernt werden. Die Teilnehmer sollen nachher schlauer sein. Was das ist, sei einmal dahingestellt. Ich nehme irgendeinen fachlichen Aspekt an. Ilker lässt auch das frei in seiner Definition – konkretisiert jedoch in der normalen Praxis. Test-Driven Development scheint mir am ehesten die Praktik, die das Dojo als Lerninhalt zu vermitteln versucht.

Wichtiger als der Lerninhalt ist mir an dieser Stelle jedoch, wie der erreicht wird. Steffen und andere favorisieren ein “Peer-Learning”, d.h. ein Lernen irgendwie ohne Lehrer, sondern von Teilnehmern auf mehr oder weniger gleicher Kenntnisstufe. Dazu gleich mehr.

Das ist ein valider Ansatz – allerdings kann ich dahinter nur Ernsthaftigkeit erkennen, wenn im Rahmen des Dojo auch eine Überprüfung stattfindet, ob das Ziel erreicht wurde. Wie findet aber eine Lernerfolgskontrolle statt? Bei den Dojos, die ich erlebt habe – sorry to say –, habe ich davon wenig gesehen.

Am Ende Spaß gehabt zu haben, ist keine Lernerfolgskontrolle in Bezug auf ein fachliches Ziel. Auch Funktionalität hergestellt zu haben, ist keine Lernerfolgskontrolle. Wie also stellen sich Steffen und die anderen es sich vor, den Lernerfolg in Bezug auf TDD oder anderes festzustellen? Solange der Anspruch existiert, dass nur ein ganz bestimmter Stil ein rechtes Dojo ausmacht, solange sollte auch klar gemacht werden können, wie denn dieser Stil seinen Erfolg sicherstellt.

Lernen von einander: Das Lernen in der Gruppe ist eine gute Sache. Lernen ist eine durchaus soziale Angelegenheit. Und Lernen ohne Machthierarchie ist auch wunderbar. Da bin ich dabei und finde es toll, das Ilker sich für einen solchen Lernprozess als “Facilitator” immer wieder zur Verfügung stellt. (Und nicht nur das! Ilker ist auch nimmermüder Motivator der Dojo-Sache. Das ist nicht zu unterschätzen.)

Ein Facilitator überwacht jedoch nur einen Prozess. Läuft alles gem. Prozessregelwerk? Tanzt keiner aus der Reihe? Gibt es keine Hindernisse, die dem Prozess im Wege stehen? Das im Blick zu behalten, ist Ilkers Sache.

Das bedeutet im Umkehrschluss und zur Entlastung von Ilker: Die Wissensvermittlung bzw. –generierung ist Sache der Teilnehmer.

Wie funktioniert das aber nur? Die Prämisse ist, dass es ein zu erlangendes Wissen gibt. Irgendwo hängt im Raum eine Latte (immer höher), die das Dojo überspringen soll. Aber wo hängt die? Wer weiß es, wenn kein “Lehrer” anwesend ist/sein darf?

image Leider, leider muss ich sagen, dass der Anspruch eines “Community Lernens”, bei dem alle gleich sind in der Diskussion, zwar schön ist – mir jedoch wenig effektiv und effizient erscheint. Es drängt sich mir das Bild eines Debattierclubs auf, in dem alle eine Meinung haben, es aber keiner so genau weiß.

Allemal solange keine systematische Ergebniserarbeitung und –sicherung stattfindet, wird da schnell viel geredet, die Energie fließt – nur wohin?

Wie gesagt: dass am Ende irgendwie Code läuft, ist mir nicht genug.

Wenn alle gleich “ahnungslos” sind, wer stellt am Ende fest, ob eine Lösung wirklich gut ist (oder zumindest besser als eine andere)? Gefühle haben dazu natürlich alle; und ein Durchschnittsgefühl lässt sich auch ermitteln. Solange wir jedoch den Anspruch haben, in einer Branche zu arbeiten, in der es auch mal gesichertes, also überindividuelles und geschmacksunabhängiges Wissen gibt, ist mir auch das zuwenig.

Übungsgruppen in der Universität arbeiten auch zusammen. Doch sie arbeiten in den Grenzen eines Korrektivs. Am Ende müssen sie ihre Ergebnisse präsentieren. Und die werden mit dem kanonischen Wissen verglichen. (Ausdrückliche Forschung, d.h. die Generierung neuer Erkenntnisse nehme ich hier aus.)

Beim Coding Dojo ist das zumindest nach dem Ideal einiger per Definitionem nicht der Fall; das nimmt kein kanonisches Wissen an – so scheint es mir zumindest. Wie also – das möge man mir erklären – kann ein Teilnehmer dann sicher sein, etwas zu lernen, wenn letztlich die anderen nicht schlauer sind als er – oder zumindest keine Rolle einnehmen dürfen, in der sie ihre Erkenntnisse gezielt den anderen vermitteln?

Man möge mich nicht falsch verstehen! Ich rede keiner Lehrerattitüde das Wort. Und der Wissenskörper befindet sich für mich immer im Fluss. Auch kann aus meiner Sicht Lernen immer nur jeder selbst; ein Lehrer ist bestenfalls Facilitator. (Im Clean Code Developer Camps haben Stefan Lieser und ich deshalb spaßeshalber das Ideal, dass das Lernen am besten funktioniert, wenn wir nur noch Kaffee ausschenken müssen und der Rest von selbst läuft ;-)

image Doch auch wenn der Wissenskörper im Fluss ist, hat er eine vom Einzelnen unabhängige (vorübergehende) Form, die zu erkennen sich lohnt. Zu der mögen TDD, Lambda Ausdrücke oder Funktionale Programmierung gehören. All das kann man besser oder schlechter tun. Aber wer weiß, ob eine Coding Dojo Gruppe es eher besser oder eher schlechter tut? Der Spaß an der Sache ist kein wirklicher Gradmesser dafür.

Mir geht es nicht darum, eine bestimmte Person auszuloben, die “es” besser weiß. Auch ich weiß nicht alles besser – aber von manchem glaube ich schon, dass ich es besser als manche weiß. Und so geht es mit anderen Themen anderen Community-Mitgliedern. Jeder weiß etwas – und auch mal besser als andere. Ist halt so. Und ist gut so.

Warum soll dann nicht der, der ein Thema besser beherrscht als andere, diese anderen anleiten? Warum muss Coding Dojo bedeuten, dass ohne Lehrer gearbeitet wird? Das will mir nicht in den Kopf.

Woher der Lehrer kommt, ist ja egal. Und über die Didaktik und Methodik lässt sich auch noch trefflich diskutieren.

Wenn es aber einen Lehrer gibt, also einen mit Wissensvorsprung, warum soll der nicht die anderen anleiten? Das halte ich für die effizientes Form des Lernens. Wir müssen uns ja nicht dümmer stellen als wir sind. Wie die Kinder zu lernen, also alles selbst herausfinden, ist eine romantische Vorstellung. Kinder lernen allerdings so, weil sie oft nicht anders können. Besser lernen sie, wenn man sie geeignet anleitet. Dann kann man nämlich das Verhältnis von Erfolg und Misserfolg steuern. Die Lernerfahrung ist dann eher motivierend.

Meine Zieldefinition

Und was ist der langen Rede kurzer Sinn? Was ist meine Definition von Coding Dojo? Hier Stichpunkte:

  • Coding Dojo bedeutet lernen in Gemeinschaft
  • Coding Dojo bedeutet den Willen zu Clean Code (Development)
  • Coding Dojo bedeutet, zunächst den state-of-the-art zu erarbeiten
  • Coding Dojo bedeutet, Code zu produzieren
  • Coding Dojo bedeutet Ergebnissicherung
  • Coding Dojo bedeutet, über das Lernen zu reflektieren
  • Coding Dojo bedeutet, Spaß mit gleichgesinnten Entwicklern zu haben

Das sind eine Menge Eckpunkte für ein Coding Dojo. Damit die alle verlässlich angelaufen werden, ist eine Moderation nötig. Ilker, du hast also auch in meinem Bild einen Job ;-)

Diese Eckpunkte spannen einen Raum auf, das Dojo. Wie das dann konkret mit Leben gefüllt wird, ist eine andere Sache. Ob Katas gemacht werden (kleine Aufgaben) oder über mehrere Sitzungen mit Hausaufgaben Projekte realisiert, das ist egal. Ob einer den anderen etwas vermittelt oder nicht, auch das ist mir letztlich egal – allerdings habe ich da so meine Meinung, wie effektiv das Lernen ist, wenn alle aus ihrer eigenen Unsicherheit heraus versuchen, Sicherheit zu erlangen. Das kann funktionieren – ist dann aber Forschung. Wer als pragmatischer Entwickler will aber forschen mit all dem, was an dem Begriff hängt?

Und nun kommt die Community. Was macht ein Dojo aus? Was gibt es diesen Eckpunkten hinzuzufügen? Was muss weg? Oder braucht es gar keine Definition und jeder macht einfach so für sich etwas und nennt es nur, wie die anderen?

Für mehr Qualität im Netz durch Identität [OOP 2010]

Auch mal anonym sein dürfen, ist ne schöne Sache. Keine Frage. Deshalb lieben wir das Bargeld immer noch. Ihm haftet nichts von uns an; damit können wir genauso Geschenke wie “Schmuddelkram” kaufen, ohne dass eine Spur auf dem Bankkonto entstünde, die uns verraten könnte.

Und auch sonst finden wir es entspannend, nicht überall und immer erkannt zu werden. Die Berühmten beneiden wir ja eher nur, solange wir nicht unter einer “Beobachtung” wie sie stehen. Wir verstehen, dass ihre hohen Gagen auch “Schmerzensgeld” sind zur Kompensation des Verlustes von Privatsphäre und Anonymität.

Das Internet schließlich hat die Anonymität zur Lebensweise erhoben. Wer hat in ihm nicht gleich mehrere Identitäten? In Diskussionsforen herrscht die Anonymität; kaum ein Eintrag wird mit Realname gemacht:

image

Das ist die ersten 25 Jahre online Foren witzig gewesen, würde ich sagen. Aber inzwischen finde ich es kontraproduktiv in seiner Selbstverständlichkeit. Warum?

 Weil Identität für mich mit Vertrauen und Qualität zu tun hat.

imageWer kennt nicht Flame-Kommentare, wer kennt nicht Trolle in Foren, wer kennt nicht die anonymen Rezensenten von Büchern, Musik und Software? Rechts als Beispiel ein Ausschnitt aus einer Liste von Buchbeurteilungen bei Amazon. Was soll ich von der Meinung von “Ein Kunde” oder “Sonja H.”  oder “fionara” halten? Nichts. Es ist egal, ob sie gut oder schlecht bewerten. Ich kann ihnen nicht vertrauen – allemal, da ich weiß, dass Verlage Rezensionen in Auftrag geben. Gute wie schlechte (für Werke anderer Verlage, versteht sich ;-)

Wer anonym bleibt, investiert nichts. Nicht mal seinen “guten Namen”.

Ohne Investition ist aber keine Ernsthaftigkeit zu erwarten. Ohne Investition ist auch nicht zu erwarten, dass jemand den Empfänger respektiert. Denn Disrespekt hat ja keine Konsequenz.

Konsequenzlosigkeit führt denn auch zu den tollsten Blüten: vom Flame-Kommentar bis zu Vandalismus und Schlimmerem.

Das wissen wir alle – und doch haben wir ein merkwürdig ambivalentes Verhältnis zu Identität und Anonymität. Wir möchten selbst anonym bleiben, hätten es aber gern, dass andere ihre Identität enthüllen. Das kann jeder an sich selbst beobachten, wenn er “gezwungen” wird, sich mit seinem richtigen Namen irgendwo im Internet anzumelden – und sich andererseits aufregt über unflätige Bemerkungen in anonymen Foren.

Ich will nicht abstreiten, dass Anonymität Vorteile hat – zum Beispiel für die “guten Kräfte” in totalitären Regimen. Ich will auch nicht abtun, dass anonyme Beiträge hohe Qualität haben können. Und schließlich erkenne ich auch an, dass ein Avatar/Nick zu einer Identität mit eigenem Wert werden kann; die mag von einer realen Person entkoppelt sein und doch vertrauenswürdig sein. (Dazu braucht es allerdings einige Zeit und wiederkehrende positive Erfahrungen mit dem Avatar/Nick.)

Unterm Strich möchte ich Anonymität also nicht grundsätzlich missen. Weder in der realen, noch in der digitalen Welt.

Dennoch plädiere ich dafür, dass wir uns öfter “zu erkennen geben”. Ich glaube, einfach daran, dass unsere Kommunikation effektiver und effizienter wird, wenn wir identitätsvoll kommunizieren. Ich melde mich daher immer öfter bei Plattformen mit meiner realtweltlichen Identität an (wobei ich mir Abkürzungen erlaube, solange ich über weitere Informationen identifizierbar bin). Das ist für mich eine Form von Investition oder Geben. Denn wenn ich nicht bereit bin, mich als Person (bekanntzu)geben und damit auch verletzlich zu machen, wie kann ich dann erwarten, dass andere das tun? Ohne Identität und Verletzlichkeit ist jedoch kein (zügiger) Vertrauensaufbau möglich. Und ohne Vertrauen kann ich nicht erwarten, dass irgendjemand sich bemüht. Und ohne Bemühen kann ich nicht auf Qualität hoffen.

imageGerade in unserer Branche, wo alle nach Qualitätsinformationen hungern, finde ich es wichtig, dass wir uns – wo immer möglich – persönlich, d.h. mit unseren realen Identitäten “in die Augen schauen” (auch wenn wir uns nicht gegenübersitzen, sondern nur chatten oder Forennachrichten austauschen).

Wir erwarten von unseren Kommunikationspartner in Twitter, Facebook, Google Groups, Blogosphere das Beste? Wir erwarten, dass Sie uns ernsthaft informieren? Und umgekehrt erwarten wir, dass andere uns ernst nehmen, wenn wir bloggen, twittern, kommentieren? Dann sollten wir als Minimum unsere Identität investieren. Kommen wir aus unserem Anonymitätsschneckenhaus heraus! Profil zeigen, Rückgrat strecken. Ja, auch wenn es mal kontrovers werden sollte.

Das Gute am Internet ist, dass wir vielfach anonym bleiben können. Wir haben die Wahl. Solange wir uns aber reflexartig für die Anonymität entscheiden, nutzen wir sie nicht. Erwachsener Umgang mit dem Internet bedeutet deshalb für mich, dass wir uns immer wieder diese Wahlmöglichkeit bewusst machen – und sie dann auch nutzen, indem wir uns für die Identität entscheiden.

Denn was können wir von einer Kultur der Anonymität, die letztlich für Unsicherheit, Angst und Grenzziehung steht, erwarten? Unsicherheit, Angst und Grenzen gebähren Unsicherheit, Angst und Grenzen - und deren Gegenteile: Sicherheitsdenken, Gewalt, Narzismus. Negative Extreme führen zu negativen Extremen.

Aber was gebiehrt der Wille zur Idendität, der Mut, Vertrauen, Offenherzigkeit, Rückgrat, Wohlwollen, Verletzlichkeit erfodert? Ich bin optimistisch, dass daraus mehr Mut, mehr Vertrauen, größere Offenherzigkeit, mehr Rückgrat, mehr Wohlwollen und mehr Sensibilität entstehen. Und wer wollte das nicht?

Zum Glück können wir alle dafür etwas tun. Mit ein bisschen weniger Anonymität jeden Tag ist ein erster Schritt getan.