The Wayback Machine - https://web.archive.org/web/20111228070830/http://blog.aztec-project.org:80/

Um unsere ASP.NET-MVC2-Kenntnisse mal wieder etwas aufzufrischen, haben ein paar von uns das zweitägige Webcamp von Microsoft in München/Unterschleißheim besucht, an dem man unter den Teilnehmern auch ein paar bekannte Gesichter wie Pete Sacchet, Christian Deger und Golo Roden angetroffen hat.

Am ersten Tag wurden die Grundlagen von MVC2, Entity Framework, JQuery und IIS vermittelt. Dabei wurde anhand einer Rich Web Application gezeigt, wie MVC2, das Entity Framework und JQuery zusammenspielen können. Am zweiten Tag mussten die am Vortag zusammengestellte Teams ein Projekt auf diesen Themengebieten basteln und vorstellen.

Moderiert wurde das Ganze von Jon Galloway und Christian Wenz, die am zweiten Tag bei Problemen mit Rat und Tat zur Seite standen.

Erhofft hatten wir uns von den zwei Tagen, einiges über MVC2 und JQuery zu erfahren. Enttäuscht wurden wir nicht, da uns noch unbekannte HtmlHelper, Validierungsmethoden sowie ein paar Tricks im Umgang mit Visual Studio gezeigt wurden. Das Entity Framework einmal im Einsatz zu sehen, war ganz nett, aber für uns nicht allzu interessant, da wir im Moment mit NHibernate arbeiten und damit ganz gut fahren.

Ja, zu essen gab es auch was. War lecker, wie man sieht. :P

Als Projekt am zweiten Tag haben wir uns für ein Buchungssystem von Ferienwohnungen entschieden. Wir waren leider nicht offiziell dabei, da uns diese Idee erst nach den Pitches eingefallen ist.
Das einzig Negative an der ganzen Veranstaltung war das Netz im Hotel Dolce Munich. 100 Leute, die gleichzeitig versuchen, über eine gefühlte DSL-Leitung zu saugen, saugt einfach. Der Proxy des Hotels setzte noch einen drauf und leitete Aufrufe auf localhost um, was den Start der Applikation in der Entwicklungsumgebung sehr schwer machte :>.

Nachdem man dann das WLAN deaktiviert hatte, konnte es dann auch losgehen.

Um uns möglichst nah an den Projekten in der Arbeit zu orientieren, haben wir erstmal Folgendes gemacht: SVN angelegt, Features, die wir aufnehmen wollten, erörtert, Architektur gezeichnet, Komponenten herausgearbeitet, Contracts erstellt, Komponenten angelegt, Komponenten implementiert. Und schwupps war die Zeit um. :> Wir sind leider nicht mit unserem Projekt fertig geworden, haben aber trotzdem in den zwei Tagen einiges gelernt.

Glückwunsch nochmal an die Gewinner des Wettbewerbs (Schiffe versenken).

kick it on dotnet-kicks.de

Share

Comments 2 Kommentare »

Dieses Wochenende findet das BarCamp Bodensee 2010 statt. Ich war gestern dort und habe interessante Sessions besucht.

Sehr gut fand ich die Session “Decentralized Social Web”, nachdem ich schon lange selbst über das Thema nachgedacht habe. In der Session wurde gut herausgearbeitet, Grundgedanke ist ein Protokoll wie IP zu schaffen, also ein Konzept zu entwickeln um die Daten seiner Friends und sozialen Kontakte selbst zu besitzen und diese bei sozialen Netzwerken dann zu verwenden. Der Betreiber eines sozialen Netzwerks selbst soll die Daten nicht besitzen bzw. nur in verschlüsselter Form auf sie zugreifen können. Ändert man selbst die Zugriffsrechte, besitzt die Plattform zwar noch die Daten, kann auf diese jedoch nicht mehr zugreifen.

Noch verstehen Nutzer den Mehrwert nicht und die Lösungen sind zu komplex, um dem Normaluser hier den Einstieg zu erleichtern. Ein Nutzer von sozialen Netzwerken möchte einen Service und den bekommt er derzeit bei Facebook. Diese Entwicklung ist gefährlich, da sich Facebook zur allgemeinen Datensammelstelle entwickelt, die alles kontrolliert. “My data belongs to me”. Nur sind wir technisch affinen Menschen hier zu paranoid? Der Normaluser bekommt im Moment genau das, was er möchte: eine gesicherte, schnelle Dienstleistung. Auf die Frage, wer für Facebook zu zahlen bereit wäre, kamen erstaunlich viele Meldungen, man sieht Facebook also als einen Dienstleister.

Gut jedoch zu sehen, dass sich bereits Projekte aufgetan haben das decentralized social web zu erkunden:

Movim
Ziel des MOVIM-Projekts (für My Open Virtual Identity Manager), ist eine vollständige und total dezentrale soziale Platform zu entwickeln, die ihre User einfach respektiert.
http://www.movim.eu/

Diaspora
The privacy aware, personally controlled, do-it-all, open source social network.
http://joindiaspora.com/

Web Finger
Personal Web Discovery, making email addresses readable again
http://code.google.com/p/webfinger/

Es gab noch viele weitere gute Sessions, das Wetter hat gestern gut mitgespielt und viele Teilnehmer haben sich gerne in der Sonne aufgehalten und dort genetzwerkt.

Die love coaches von be2 waren auch wieder dabei und verlosen heute eine faltbare Sitzcouch, die Flexible Love Bank von myfab.

Share

Comments 3 Kommentare »

Nach dem ich meinen vorherigen Artikel zum Thema “Asynchrone Kommunikation mit dem Async-Pattern” vorgestellt hatte, hat Ralf Westphal auf seinem Blog “One Man Think Tank Gedanken” das Vorgehen zur Implementierung einer asynchronen Kommunikation mit Hilfe von Event-Based-Components vorgestellt, welches eine sehr gute Alternative zum Async-Pattern ist. Seinen Eintrag nehme ich zum Anlass, um meine Beispiel-Implementierung des Async-Pattern zu refaktorisieren, um eine bessere Trennung der Verantwortlichkeiten und somit eine bessere Lesbarkeit zu erreichen.

In das Form wird die Abhängigkeit “CalcProxy” injected.

static void Main()

{

    CalcProxy calcProxy = new CalcProxy(new Calculator());

    Application.EnableVisualStyles();

    Application.SetCompatibleTextRenderingDefault(false);

    Application.Run(new Form1(calcProxy));

}

 

Im Gegensatz zur vorherigen Version wird in der Form nun nicht mehr der Calculator direkt erzeugt und verwendet, sondern auf den injekteten CalcProxy zugegriffen.

public partial class Form1 : Form {

    private readonly ICalcProxy m_calcProxy;

    public Form1(ICalcProxy calcProxy) {

        InitializeComponent();

        m_calcProxy = calcProxy;

        m_calcProxy.CalcCompleted += CalculatorCalcCompleted;

    }

 

    private void Run_Click(object sender, EventArgs e) {

        int number;

        if (Int32.TryParse(txbEingabe.Text, out number)) {

            m_calcProxy.CalcAsync(number, number);

        }

    }

 

    void CalculatorCalcCompleted(object sender, CalcEventArgs eventArgs) {

        lblCounter.Text = eventArgs.UserState.ToString();

    }

}

 

Der CalcProxy wiederum bekommt die Abhängigkeit zum Calculator injected und stellt für die Calculator.Calc-Methode sowohl eine synchrone als auch eine asynchrone Methode zur Verfügung.

public class CalcProxy : ICalcProxy {

    private readonly ICalculator m_calculator;

    public event CalcCompletedEventHandler CalcCompleted;

    private AsyncOperation m_asyncOperation;

    private bool m_isRunning;

 

    public CalcProxy(ICalculator calculator) {

        m_calculator = calculator;

    }

 

    public int Calc(int number) {

        return m_calculator.Calc(number);

    }

 

    public void CalcAsync(int number, object userState) {

        lock (this) {

            if (m_isRunning) {

                throw new InvalidOperationException("Diese Operation wird bereits ausgeführt");

            }

            m_isRunning = true;

            m_asyncOperation = AsyncOperationManager.CreateOperation(userState);

            ThreadPool.QueueUserWorkItem(ExecuteCalc, number);

        }

    }

 

    private void ExecuteCalc(object state) {

        var result = Calc((int)state);

        m_asyncOperation.PostOperationCompleted(CalcCompletedSuccessful, result);

    }

 

    private void CalcCompletedSuccessful(object result) {

        if (CalcCompleted != null) {

            CalcCompleted(this, new CalcEventArgs(null, false, (int)result, result));

        }

    }

}

 

Nun enthält der Calculator nur noch die Methode die für den Calculator notwendig ist, nämlich die Calc-Methode.

public class Calculator : ICalculator {

    public int Calc(int number) {

        Thread.Sleep(10000);

        return number * number;

    }

}

kick it on dotnet-kicks.de

Share

Comments 4 Kommentare »

Bevor ich anhand eines Beispiels zeige, wie man mit Hilfe des Async-Pattern ein asynchrone Kommunikation implementieren kann, möchte ich kurz beschreiben, wo der Unterschied zwischen der synchronen und der asynchronen Kommunikation liegt und wofür die asynchrone Kommunikation nützlich ist.

Synchrone Kommunikation

Bei der synchronen Kommunikation handelt es sich um eine Echtzeit-Kommunikation. Das bedeutet, dass Anfragen und Antworten jeweils vollständig nacheinander abgearbeitet werden. Kommuniziert ein Prozess mit einem Webserver synchron, so ist der Prozess solange blockiert, bis er die vollständige Antwort vom Webserver erhalten hat.

Asynchrone Kommunikation

Im Gegensatz zur synchronen Kommunikation handelt es sich bei der asynchronen Kommunikation nicht um eine Echtzeit-Kommunikation. Das bedeutet, dass bei der Kommunikation eines Prozesses mit einem Webserver der Prozess nicht blockiert. Der Prozess verschickt lediglich die Anfrage an den Webserver und kehrt danach sofort zur weiteren Prozessausführung zurück. Der Prozess geht dabei davon aus, dass die Anfrage an den Webservice korrekt gestellt wurde. Die Antwort wird dann zu einem unbestimmten Zeitpunkt vom Webservice geliefert, und zwar dann, wenn dieser mit der Abarbeitung der Anfrage fertig ist.

Warum Asynchrone Kommunikation

Asynchrone Kommunikation bietet sich in unterschiedlichsten Situationen an. So ist es z.B. sinnvoll, dass eine WinForms-Anwendung asynchron mit einem Webservice kommuniziert, da der Haupt-Thread der WinForm-Anwendung sonst so lange blockiert wäre, bis der Webservice die Antwort auf die Anfrage liefert. Die Folge wäre, dass im Titel der Anwendung stehen würde, dass die Anwendung nicht antwortet (s. Abbildung 1). Viele Benutzer denken dass es sich bei dieser Meldung um einen Fehler im Programm handelt und beenden das Programm fix über den Task-Manager. Dabei lag es nur an der etwas länger dauernden Kommunikation zwischen der WinForm-Anwendung und dem Webservice.

Abbildung 1

Ein weiterer Grund für eine asynchrone Kommunikation wäre, wenn eine Anwendung nur Nachrichten verschicken möchte und es im Grunde keine Rolle spielt, ob diese Nachricht korrekt verarbeitet wurde. Vorstellbar wäre hier Loggen von Aktionen. Mir wäre es jetzt egal, ob die Nachricht korrekt gespeichert wurde oder nicht. Ich will nur nicht, dass meine Anwendung, nur weil Daten geloggt werden müssen, langsamer wird. Es handelt sich ja bei den Log-Daten nicht um Informationen die für die Abarbeitung notwendig sind.

Ein weiterer Fall wäre z. B. das Skalieren von Datenbankabfragen. So könnten mehrere Threads gleichzeitig Daten von gleichen oder unterschiedlichen Datenbeständen abfragen um schnellere Antwortzeiten zu erhalten.

Beispiel

Um die asynchrone Kommunikation zu realisieren gibt es unterschiedliche Möglichkeiten. Ich habe mich allerdings für eine Event-Based-Variante entschieden. Der große Vorteil von einem Event-Based Async-Pattern liegt in meinen Augen darin, dass der Nutzer von asynchrone Methoden sich nicht wirklich mit Multithread-Umgebungen auskennen muss. Für den Nutzer ist es völlig transparent wie die Threads im Hintergrund erzeugt werden und wie die Synchronisation der einzelnen Thread funktioniert. Für den Nutzer ist es nur wichtig zu wissen, dass er eine Methode aufrufen kann die asynchron abläuft und somit nicht den erwarteten Rückgabewert besitzt wie die synchrone Methode und dass ein Event ausgelöst wird, wenn die Methode komplett abgearbeitet wurde und der erwartete Rückgabewert zur Verfügung steht.

Nun aber genug geredet, jetzt wird programmiert. Für das Beispiel habe ich mich für eine WinForm-Anwendung entschieden, die nichts anderes tut, als die eingegebene Zahl zu quadrieren. Diese Berechnung dauert aufgrund eines Thread.Sleep() zehn Sekunden, um eine verzögerte Ausführung zu simulieren. Die Berechnung habe ich dabei in eine extra Komponente ausgelagert, die eine Schnittstelle zur asynchronen Kommunikation bereitstellt. Dabei gilt es eine gewisse Namenskonvention einzuhalten. Neben der synchronen Methode „Calc“, wird die asynchrone Methode mit dem Zusatz „Async“ bezeichnet („CalcAsync“). Da das Async-Pattern Event-Based ist, muss ein Event bereitgestellt werden, welches ausgelöst wird, wenn die asynchrone Verarbeitung beendet wurde. Laut Namenskonvention muss solch ein Event „<Methodenname>Completed“ heißen. Mein Event heißt somit „CalcCompleted“.

Die Abbildung 2 zeigt die UI der Anwendung. Bei dem Drücken des „Run“-Buttons, soll die eingegebene Zahl asynchron quadriert werden und im Anschluss in das Feld „Ergebnis“ ausgegeben werden.

Abbildung 2

Der Code hinter der UI sieht folgendermaßen aus. Beim instanziieren des Forms, wird eine Instanz des Calculators erstellt und ein Delegate auf das „CalcCompleted“-Event registriert. Dieses Event wird aufgerufen sobald der Calculator mit der Berechnung fertig ist.

Bei dem Drücken des „Run“-Buttons, wird die Methode Calculator.CalcAsync(…) aufgerufen.

public partial class Form1 : Form {

        private ICalculator m_calculator;

        public Form1() {

            InitializeComponent();

            m_calculator = new Calculator();

            m_calculator.CalcCompleted += Calculator_CalcCompleted;

        }

 

        private void Run_Click(object sender, EventArgs e) {

            int number;

            if (Int32.TryParse(txbEingabe.Text, out number)) {

                m_calculator.CalcAsync(number, number);

            }

        }

 

        void Calculator_CalcCompleted(object sender, CalcEventArgs eventArgs) {

            lblCounter.Text = eventArgs.Result.ToString();

        }

    }

Sobald die Berechnung fertig ist, wird das CalcCompleted-Event ausgelöst und somit die Calculator_CalcComplete-Methode aufgerufen und das Ergebnis der Berechnung in ein Label geschrieben. Der große Vorteil ist, dass man sich an dieser Stelle nicht mehr um die Synchronisierung der Threads kümmern muss, sodass man direkt auf das Label schreiben darf und es nicht zu einem threadübergreifenden Zugriff kommt.

Der Calculator sieht wie folgt aus:

       

public interface ICalculator {

        event Calculator.CalcCompletedEventHandler CalcCompleted;

        int Calc(int number);

        void CalcAsync(int number, object userState);

    }

 

    public class Calculator : ICalculator {

        public delegate void CalcCompletedEventHandler(object sender, CalcEventArgs eventArgs);

        public event CalcCompletedEventHandler CalcCompleted;

        private AsyncOperation m_asyncOperation;

        private bool m_isRunning;

 

        public int Calc(int number) {

            Thread.Sleep(10000);

            return number * number;

        }

 

        public void CalcAsync(int number, object userState) {

            lock (this) {

                if (m_isRunning) {

                    throw new InvalidOperationException("Diese Operation wird bereits ausgeführt");

                }

                m_isRunning = true;

                m_asyncOperation = AsyncOperationManager.CreateOperation(userState);

                ThreadPool.QueueUserWorkItem(ExecuteCalc, number);

            }

        }

        .

        .

        .

    }

Wie man im Interface des Calculator sieht, gibt es eine synchrone und eine asynchrone Methode für die Berechnung. Uns interessiert allerdings nur die asynchrone Methode. Das lock und die Prüfung auf m_isRunning verhindern lediglich, dass die asynchrone Methode während ihrer Ausführung öfter aufgerufen wird. Das Wesentliche an dieser Methode ist der Aufruf von AsyncOperationManager.CreateOperation, denn dieser Aufruf stellt einen Synchronisationskontext bereit, der die Threads miteinander synchronisiert. Für die eigentliche Berechnung wird sich über den ThreadPool ein neuer Thread besorgt, der sich dann um die Abarbeitung der ExecuteCalc in einem eigenen Thread kümmert.

public class Calculator : ICalculator {

        .

        .

        .

        private void ExecuteCalc(object state) {

            int result = Calc((int)state);

            m_asyncOperation.PostOperationCompleted(CalcCompletedSuccessful, result);

        }

 

        private void CalcCompletedSuccessful(object result) {

            if (CalcCompleted != null) {

                CalcCompleted(this, new CalcEventArgs(null, false, (int)result, result));

            }

        }

    }

    public class CalcEventArgs : AsyncCompletedEventArgs {

        public CalcEventArgs(Exception error, bool cancelled, int result, object userState)

            : base(error, cancelled, userState) {

            Result = result;

        }

        public int Result { get; private set; }

    }

Sobald die Berechnung abgeschlossen ist, wird der Thread mit dem MainThread über den Aufruf von PostOperationCompleted synchronisiert und das CalcCompleted-Event ausgelöst und das Ergebnis in das Label geschrieben (s. o.).

6 public partial class Form1 : Form {

7 private ICalculator m_calculator;

8 public Form1() {

9 InitializeComponent();

10 m_calculator = new Calculator();

11 m_calculator.CalcCompleted += Calculator_CalcCompleted;

12 }

13

14 private void Run_Click(object sender, EventArgs e) {

15 int number;

16 if (Int32.TryParse(txbEingabe.Text, out number)) {

17 m_calculator.CalcAsync(number, number);

18 }

19 }

20

21 void Calculator_CalcCompleted(object sender, CalcEventArgs eventArgs) {

22 lblCounter.Text = eventArgs.UserState.ToString();

23 }

24 }

kick it on dotnet-kicks.de

Share

Comments 3 Kommentare »

Obwohl wir Jeff Atwood schon vor Monaten von unseren Bloggerliste gestrichen haben, ich habe ihn noch nicht aus meinem Googlereader entfernt. Er ist ein Typ, der liebt viel Wirbel zu verursachen (Scott Hanselmann nennt ihn aus den Wörtern friend und enemy “my friendemy” ;) ) aber manchmal trifft er den Nagel auf den Kopf. So auch in seinem letzten Artikel “The Non-Programming Programmer”.


I wrote that article in 2007, and I am stunned, but not entirely surprised, to hear that three years later “the vast majority” of so-called programmers who apply for a programming job interview are unable to write the smallest of programs. To be clear, hard is a relative term — we’re not talking about complicated, Google-style graduate computer science interview problems. This is extremely simple stuff we’re asking candidates to do. And they can’t. It’s the equivalent of attempting to hire a truck driver and finding out that 90 percent of the job applicants can’t find the gas pedal or the gear shift.

Aus den Unmengen von Kommentaren zu urteilen, ist das ein Problem, mit dem sehr viele zu kämpfen haben. Sein Artikel beschäftigt sich mit der Arbeit von Personen, die Einstellungsgespräche führen, und er versucht ein paar Tipps zu geben, wie man dieses Verfahren führen soll.

Ich musste allerdings beim Lesen ständig auf die Situation “danach” denken, wenn diese NPPs (sprich Non- Programming Programmers) bereits aus irgendeinem Grund eingestellt wurden. Aus Erfahrung weiß ich genau, was mir viel über jemanden verraten würde: weiß er/sie etwas über Clean Code, kennt er die Folgen vom Creepy Code und wie ist die persönliche Einstellung dazu? Also zusammengefasst: geht es um einen professionellen Softwareentwickler? Dafür würden auch ein Code-Review oder ein paar Fragen reichen.

Was haltet ihr von Coding bei der Einstellung? Ist das auch in Europa üblich? Würde das die unpassenden Personen ausfiltern? Oder soll man sich die Zeit nehmen und dem Kandidaten “ungesehen” die Probezeit anbieten? Würde das vielleicht zu viele Personen ausfiltern? Kann man sich das überhaupt erlauben in der heutigen Zeit der Fachkräftemangel? (Gut, man fragt sich natürlich, ob wir hier über “Fachkraft” sprechen dürfen…)

kick it on dotnet-kicks.de

Share

Comments 14 Kommentare »

Seit ein paar Monaten wird der Begriff NoSQL (Not only SQL) immer häufiger verwendet. Wir sind mit unserer schemalosen Datenbank StupidDB vor eineinhalb Jahren bereits auf diesen Zug aufgesprungen und jetzt hat sie einen Überbegriff bekommen: auch StupidDB ist NoSQL!

Auf dem BarCamp in Nürnberg war NoSQL auch ein Thema und Jonathan Weiss hat in seiner Session gut dargestellt, dass relationale Datenbanken nicht immer die Lösung für alle Probleme sind. NoSQL Datenbanken speichern meist dokumentenorientiert und sind dadurch nicht an ein festes Schema gebunden. Relationale Datenbanken haben ein fixes Schema und erlauben dynamische Abfragen der Daten, bei NoSQL ist dies umgekehrt. Weitere Informationen zu NoSQL bei Wikipedia.

Im März Heft der dotnetpro stelle ich ausführlich den Einsatz von StupidDB vor. Das Heft ist am 18.2.2010 erschienen und sollte jetzt in jedem gut sortierten Kiosk erhältlich sein.

Für alle, die sich Heft nicht griffbereit haben, ich habe bereits Mitte letzten Jahres in einem Blogpost den Einsatz von StupidDB beschrieben. Hier sieht man zumindest die Grundzüge der StupidDB. Das aktuelle dotnetpro Heft lohnt sich jedoch trotzdem, da hier noch weitere Artikel zum Thema NoSQL zu finden sind. Unter anderem das Lounge Repository von Ralf Westphal und auch CouchDB.

Als neuester Vertreter in der NoSQL Bewegung gilt MongoDB. Eine Opensource Implementierung die nun auch Sourceforge einsetzt. Auch dafür gibt es schon Blogposts und Tests mit .NET.

Zudem hat Ayende Rahien im Herbst letzten Jahres auch seine Rhino Divan DB vorgestellt. Interessant klingt auch Object Lounge.

Es scheint also ein Bedarf an alternativer Datenpersistenz zu bestehen, wird sich zeigen wohin dieses Jahr die Reise bei NoSQL geht.

Wer sich den aktuellen Code einmal ansehen möchte, kann dies gerne unter folgendem Link ansehen:
https://stupiddb.svn.sourceforge.net/svnroot/stupiddb/trunk

Als DLL haben wir StupidDB auf www.aztec-project.org bereitgestellt.

Verwendet ihr schon NoSQL?

kick it on dotnet-kicks.de

Share

Comments 8 Kommentare »

Im Teil 1 (MVP mit WinForms) habe ich die Grundgedanken zur Implementierung von MVP in WinForms vorgestellt, mit der man WinForm-Anwendungen mit UnitTests abdecken kann. In einer komplexeren WinForm-Anwendung gibt es neben dem Startform auch mehrere Unterforms, die durch das Hauptform aufgerufen werden müssen.

Das Beispielprojekt

Zur Demonstration habe ich ein Beispielprogramm mit MVP entwickelt, welches einen sehr einfachen Twitterclient darstellt. Das Beispiel wurde nach Contract-First komponentenorientiert gebaut und besteht neben der MVP-Komponente aus weiteren Komponenten.

Die weiteren Komponenten haben nichts mit MVP zu tun, sondern sollen nur zeigen, wie man MVP in diesem Umfeld integriert. -> Den kompletten Sourcecode downloaden

Die Funktionen des Twitter-Clients sollen sein:
1. Anzeige der 20 neuesten Meldungen aus der Timeline im Hauptfenster
2. Der Benutzer soll Status-Updates bei Twitter posten können
3. Die Zugangsdaten des Twitter-Accounts sollen gespeichert werden können

Die WinForm-Komponente

Um die Funktionen abzubilden, sind 3 Screens notwendig:
1. Hauptbildschirm mit der Timeline des Twitter-Accounts
2. Form für das Absenden eines Twitter-Status-Updates
3. Konfigurationsbildschirm für den Twitter-Account

Jedes WinForm besteht aus einer View-Klasse (dem WinForm), einem Model, welches als Singleton im IoC-Container konfiguriert wird und einem Presenter. Die einzelnen Funktionen in den Views sind im Beispielprojekt durch Tests abgedeckt und zeigen die notwendigen Tests für diese Art der Implementierung. Gerade durch geringen Funktionsumfang kann man das Muster der Verwendung gut erkennen.

In der MVP-Komponente befindet sich auch der “Inversion of Control”-Container, der die einzelnen Komponenten zusammenfügt. Dies könnte auch in einer extra Runner-Komponente ausgelagert sein.

Aufrufen eines weiteren WinForms

Alle Abhängigkeiten werden per Dependency-Injection-Container an den Presenter übergeben. Da das Hauptform alle weiteren Views und Presenter instanziert, müssten diese alle bereits beim Programmstart instanziert werden. Um dies zu verhindern, habe ich eine IPresenterFactory eingeführt, die zur Laufzeit weitere Presenter nachinstanzieren kann. Die Factory selbst hält eine Referenz auf den Container und wird bei Programmstart im Container hinzugefügt. Um sicherzustellen, dass weiterhin alle anderen Abhängigkeiten über den Konstruktor definiert werden, können aus dieser Factory nur Klassen instanziert werden, die IPresenter implementieren.

Fazit
Mit dieser Beispielanwendung kann man eine mögliche Implementierung von Model View Presenter in der Variante Supervising Controller sehen. Es ist also auch mit WinForms eine voll getestete MVP-Implementierung zu erstellen.

Anhang:
Kompletter Sourcecode der Beispielanwendung als ZIP

kick it on dotnet-kicks.de

Share

Comments 3 Kommentare »

Wir haben wie viele von uns in der Webentwicklung vor vielen Jahren mit Scriptsprachen und mit prozeduralen – Spaghetti-Code ;) – angefangen. Mit der Zeit wuchs unsere Webpräsenz zu einer unüberschaubaren Anwendung mit manchen Seiten, die keiner von uns mehr anfassen wollte – aus Angst vor den Konsequenzen.

Um etwas Ordnung in die Webanwendungen zu bringen, haben wir also vor 4 Jahren angefangen, nach einem 3-Schichten-Modell zu entwickeln. Wir haben neue Funktionalitäten und neue Anwendungen nur noch so gebaut und wir waren für eine kurze Zeit zufrieden. Alles lief gut. Als wir den Umstieg auf .NET begonnen haben, haben wir weiterhin nach einem Mehr-Schichten-Modell gearbeitet, wir haben nur die Anzahl der Schichten erhöht.

Die Anwendungen wuchsen weiter, wir haben immer mehr Bereiche ausgelagert und diese hauptsächlich mit Webservices angesprochen. Währenddessen waren wir daran, unser Hauptprodukt, ein Portal für unseren Kunden mit der neuen Technologie entsprechend der alten Anforderung neu zu bauen. Und dann ist es passiert: ehe wir uns versahen, hatten wir ein riesiges Projekt, das alle mögliche Anwendungen eingebunden bzw. durch Webservices angesprochen hat. Die Grenzen waren fließend, eventuelle Änderungen an anderen Anwendungen konnten das Projekt unbuildbar machen, also ein ähnlicher Zustand wie vor paar Jahren zuvor.

Die Weiterentwicklung hat nicht nur in unserer Art zu Programmieren stattgefunden, wir selbst haben uns auch weiterentwickelt, wir haben die Community kennen gelernt. Bei den Open Space-Veranstaltungen haben wir Stefan und Ralf kennengelernt und durch sie eine andere Sichtweise der Dinge: die Modellierung einer Lösung durch Softwarezellen.

Wir haben sie zu uns eingeladen und uns die Idee erklären lassen. Das Stichwort heißt Holon. Wikipedia definiert ein Holon folgendermaßen:

Der Begriff Holon (von griech. ὅλος, hólos und ὀν, on „ganzes Seiendes“) wurde von Arthur Koestler geprägt und bedeutet ein Ganzes, das Teil eines anderen Ganzen ist. Es wird auch als “Ganzes/Teil” umschrieben.

Jede Anwendung ist ein Ganzes, die aus Teilen besteht, die ihrerseits auch als Ganze zu betrachten sind.

Seit dem Besuch von Ralf und Stefan haben wir uns die Artikelserie von Ralf von dotnetpro durchgelesen, die Webcasts (Teil 1, Teil 2) angeschaut und wir haben angefangen, diese Modellierung auszuprobieren.

Wir haben noch einen langen und interessanten Weg vor uns, aber eins ist jetzt schon sicher: wir werden versuchen unsere nächste Projekte durch Softzellen modellieren.

Solange die Komplexität nicht wieder die Überhand gewinnt ;)

kick it on dotnet-kicks.de

Share

Comments 2 Kommentare »