Schlagwort-Archive: Patterns

Einführung in IoC Container

In diesem Webcast biete ich einen kleinen Einstieg zur Verwendung von IoC Containern. Diese Frameworks helfen bei der Umsetzung des Inversion of Control Principle unter Einsatz von Dependency Injection. Damit ist es möglich gemeinsam an an einem Feature zu arbeiten und so den Work in Progress (WiP) zu minimieren.

  • Alle Blogeinträge zu Castle.Windsor samt den im Video gezeigten Code Beispielen gibt es hier.
  • Die Projekte aus dem Webcast habe ich vorübergehend hier zur Verfügung gestellt.

 

Modularisierung durch Dependency Injection

Advertisements

Workshop Test Driven Development

Nach dem DDD Workshop nahm ich ebenfalls bei Dennis an der TDD Session teil. Persönlich habe ich hier einige Erfahrungen. Angefangen bei dem praktischen Einsatz in unserem ERP System über betriebsinterne Coding Dojos bis hin zu Katas in der Karlsruhe User Group.

In dem Kontext brachte mir der Workshop leider nicht weiter. Meine eigentlichen Erwartungen waren dahingehend gerichtet:

  • Besonders gute TDD/BDD Frameworks kennen lernen
  • Best Practices für konkrete Spezialfälle (Parallelisierung, Zeitstempel, Datenbankzugriff) exerzieren

Allerdings konnte ich den Einblick bekommen, dass es (leider!) immer noch Entwickler gibt, die vom Arbeitgeber kein ReSharper zur Verfügung gestellt bekommen oder mit Windows XP arbeiten müssen. Meiner Ansicht nach ein absolutes No-Go! Hier lässt sich nur hoffen, dass ein Umdenken in den verantwortlichen Stellen noch stattfinden wird.

Workshop – Eine Zeitreise mit dem Desktop Teil 2

Nachdem ich in Teil 1 die aktuell zur Verfügung stehenden Technologien angesprochen habe, soll es nun mehr um Patterns und Clean Code Prinzipien schlechthin gehen.

Während WinForms mit seinem Code Behind in keinster Weise den Anforderungen an die Evolvierbarkeit von Code genügt, wurde mit WPF von Anfang an eine leichte Abwandlung des MVC/MVP Patterns “vermarktet”: Das Model View ViewModel Pattern.

Frank und Silvio stellen hierbei das Seperation of Concerns Principle in den Vordergrund. Besonders gut gefallen hat mir in diesem Kontext auch deren Haltung zu Domain Driven Design. Wie ich, haben sie eine von der ursprünglichen Lehre Evans abweichende Meinung bgzl. der Vermischung von Daten und Logik im selben Objekt. Ralf Westphal hat dies in den vergangenen 6 Monaten ebenfalls in einer 3-teiligen Serie in der dotnetpro (in den Heften 4, 6 und 7 2012) thematisiert.

Anmerkung: Auf dem im Juli stattgefundenen .NET Open Space Süd kam im Übrigen selbige Diskussion. Deshalb an dieser Stelle meine Aufforderung an die Community hierüber vermehrt zu bloggen.

Leider hat MVVM auch diverse Nachteile, darunter das häufige Wiederholen von gleichem bzw. ähnlichem Code. Nachdem kurz über diverse MVVM Frameworks gesprochen wurde, stellten die Referenten eine von ihnen entwickelte im Produktiveinsatz befindliche Lösung vor, die mit ca. 1000 Codezeilen recht überschaubar ist. Laut Aussagen haben sie sich dafür die Schmerzstellen in den eigenen Projekten angeschaut und das Beste für sich aus den verschiedenen Frameworks herausgepickt.

Den Code werde ich, nachdem die Zwei das Feedback des Workshops eingearbeitet haben, mit deren freundlicher Erlaubnis hier online stellen.

Webcast Strategy Pattern mit IoC

Den Webcast zu diesem Blogeintrag gibt es hier.

Strategy Pattern mit IoC sauber implementiert

Ein kurzer Hinweis vorab: Den Inhalt des Blogeintrags habe ich auch in einem Webcast zusammengefasst. Das Video gibt es auf YouTube. Den Code findet ihr hier.

In meinem letzten Blogeintrag habe ich das Strategy Pattern in der Praxis gezeigt. Primär gab es noch einen Smell, welchen ich erwähnt hatte: Das Open Closed Principle ist damit noch nicht 100%ig eingehalten und an einer Stelle heble ich mein IoC Konzept aus. Das passiert genau hier:

   1: public StateHandler(IClock clock, IBuildDefaultProposalsValues defaultValues)

   2: {

   3:     Handler = new Dictionary<SelloutStates, ICreateOrderProposal>

   4:               {

   5:                   {SelloutStates.Oversupply, null},

   6:                   {SelloutStates.Predicted, new PredictedGap(defaultValues)},

   7:                   {SelloutStates.Urgent, new UrgentGap(defaultValues, clock)},

   8:                   {SelloutStates.AppointmentWarnings, new AppointmentWarning(defaultValues, clock)},

   9:                   {SelloutStates.Unknown, null},

  10:                   {SelloutStates.Verify, new NoForecastPossible(defaultValues)},

  11:                   {SelloutStates.Ok, new UncomplicatedAppointment(defaultValues, clock)}

  12:               };

  13: }

Zum einen müsste ich die Klasse immer anpassen, wenn ich einen weiteren Status aufnehmen möchte. Zum anderen erzeuge ich mir Instanzen von Klassen, welche ich nicht über den Container erhalten habe, sprich ich hole mir die Abhängigkeiten selbst, statt mir diese gemäß Inversion of Control Principle zuweisen zu lassen. Das wäre zwar möglich gewesen, allerdings würde der Konstruktor dadurch erheblich aufblähen, weil ich pro Status eine Implementierung reinreichen müssten. Dieses Problem könnte ich über Service Location lösen, d.h. ich lasse mir lediglich den Container reinreichen und mache die Auflösung intern. Für mich persönlich auch keine schöne Lösung (Hinweis: Dafür müsste man den Container in sich selbst registrieren…).

Ob nun saubere Dependency Injection mit aufgeblähtem Konstruktor oder Service Location, in jedem Fall bliebe das Problem, dass ich jedes Mal im Container eine weitere Registrierung für einen neuen Status durchführen müsste.

Daraufhin kamen Rückfragen, wie dies am besten zu lösen sei. Das soll Thema dieses Blogeintrags und des dazu passenden Webcasts sein, v.a. weil im Netz auch nur selten saubere Implementierungen anzutreffen sind, die alle Prinzipien einhalten.

Als erstes wird der obere Code gänzlich entfernt, da dieser nicht mehr benötigt wird. Hinter dem Code steckte eigentlich das Factory Pattern. Ich lasse mir durch die Factory (abhängig vom Status) das entsprechende Objekt erzeugen und arbeite dann mit diesem weiter. Castle.Windsor als IoC Container bietet uns hierfür sogenannte interface-based factories an.

Anmerkung: Der folgende Code basiert nicht mehr auf dem bisherigen, welchen ich im vorherigen Blogeintrag verwendet habe. Im Webcast ist dazu alles erläutert und ich habe das Projekt unter Github zur Verfügung gestellt.

   1: yield return Component

   2:     .For<IchVermittleVorschlagsrechner>()

   3:     .AsFactory(c => c.SelectedWith(new VorschlagsrechnerVermittler()));

Wie man sieht, muss man lediglich das Factory-Interface, welches man zuvor selbst ausimplementiert hatte, angeben und im Anschluss ‘AsFactory’ anhängen. Als Parameter übergebe ich den Verweis auf eine Logik, welche die Factory später intern verwendet, um mir das korrekte Objekt (den korrekten Service) zurückzuliefern. Das Bedeutet, dass “new VorschlagsrechnerVermittler” der Factory, wenn auf ihr ein Aufruf stattfindet, sagen muss, was sie zurückgeben soll. Es folgt die Implementierung:

   1: public class VorschlagsrechnerVermittler : DefaultTypedFactoryComponentSelector

   2: {

   3:     protected override string GetComponentName(MethodInfo method, object[] arguments)

   4:     {

   5:         if (method.Name == "Für" && arguments.Length == 1 && arguments[0] is Bestandsstatus)

   6:         {

   7:             var status = arguments[0].ToString();

   8:             //von mir frei gewählte Konvention wie die Komponente im Container heißt

   9:             return string.Format("BerechnerFürArtikelstatus{0}", status);

  10:         }

  11:         return base.GetComponentName(method, arguments);

  12:     }

  13: }

Dieser Code macht nun genau das, was ich vorher explizit im Dictionary definiert habe, allerdings anhand einer Konvention. Die Methode in Zeile 3 liefert als String den Namen der Komponente zurück basieren auf dem Namen des Status, also z.B. ergibt sich für den Status “Ok” der Komponentenname “BerechnerFürArtikelstatusOk”.

Nun fehlt lediglich noch eine kleine Anpassung für den IoC Container. Dieser weiß bisher nichts von einer Komponente “BerechnerFürArtikelstatusOk”. Eine Möglichkeit wäre, dass ich – wie bereits eingangs erwähnt – für jeden Status die Ausprägung im Container registriere, also in diesem Fall beispielsweise so:

   1: yield return Component.For<IchErrechneArtikelZukaufsvorschlag>()

   2:     .ImplementedBy<Ok>()

   3:     .Named("BerechnerFürArtikelstatusOk")

   4:     .LifestyleTransient();

Das widerspricht immer noch dem OCP, sodass ich es wie folgt löse:

   1: yield return AllTypes.FromThisAssembly()

   2:     .BasedOn<IchErrechneArtikelZukaufsvorschlag>()

   3:     .Configure(a => a.Named(string.Format("BerechnerFürArtikelstatus{0}",

   4:         a.Implementation.UnderlyingSystemType.Name)))

   5:     .Configure(a => a.LifestyleTransient());

Zunächst hole ich mir alle Klassen aus der aktuellen Assembly, welche auf “IchErrechneArtikelZukaufsvorschlag” basieren, also alle meinen konkreten Status-Implementierungen. Im Anschluss sage ich noch, welchen Name diese Komponenten im Container bekommen sollen. Hier steht die selbe Konvention wie in dem Code Sample  zuvor. Der Vollständigkeit halber sei erwähnt, dass ich hier gegen das Don’t Repeat Yourself Principle verstoße. Dies soll lediglich der Vereinfachung im Beispiel dienen.

Ab jetzt muss ich, wenn ein weiterer Status hinzu kommt, lediglich eine Implementierung für diesen machen. Bestehender Code muss nicht mehr angefasst werden.

Streit zwischen YAGNI und Open Closed Principle

Kürzlich hatte ich ein interessantes Gespräch darüber, ob man durch die Einhaltung von OCP YAGNI über den Haufen wirft. Hintergrund war der, dass ich persönlich meine Kontrakte (Interfaces) immer in eine separate Assembly lege. Wenn die Implementierung beispielsweise in “MyProgram.Finances” liegt, dann gibt es eine “MyProgram.Finances.Contracts”, die alle in “MyProgram.Finances” verwendeten Interfaces enthält. Das ist meine persönliche Konvention für meine Programme. Aus meiner Sicht entspricht dies perfekt dem OCP, da auf diese Art jeder Entwickler in der Lage ist anhand der Contracts seine eigene Implementierung zu schreiben und diese im IoC Container über einen Installer zu registrieren. Er muss dann lediglich meine Implementierung löschen. Generell macht das ganze Vorgehen besonders bei einer IoC Architektur Sinn!

Die andere Sichtweise war nun: Warum Overengineering betreiben, wenn es sowieso nur eine Implementierung gibt und wir rein für uns entwickeln, sprich es keine Dritte gibt, die separate Lösungen anbieten wollen? Das widerspräche dem YAGNI Prinzip. Der Gegenvorschlag war also, dass alles in die gleiche Assembly kommt. Das Interface wäre immer noch Public und die Implementierung internal, da man ja weiterhin die Implementierung im IoC registriert.

Das Problem ist in dem Fall, dass man eben nicht mehr die Freiheit hat die Implementierung zu überschreiben ohne den bestehenden Code anzufassen.

Persönlich sehe ich es nicht so, dass man gegen das YAGNI Prinzip verstößt, wenn man die Interfaces in eine separate Assembly legt, da man nicht “mehr” Code entwickelt, sondern lediglich die Architektur von Anfang an offen bzw. erweiterbar hält. Natürlich hat man jetzt ein Projekt mehr, aber der eigentliche produktive Code ist der gleiche. Hingegen verstößt man imho definitiv gegen das OCP, wenn man man die Interfaces nicht separiert.

Wie seht ihr das? Feedback über Facebook, Twitter oder WordPress ausdrücklich erwünscht!

Anti Patterns–Any vs. Count

 

   1: static void Test()

   2: {

   3:     var list1 = new List<int> { 1, 2, 3, 4, 5 };

   4:  

   5:     if (list1.Count > 0)

   6:     {

   7:         Console.WriteLine("if - count");

   8:     }

   9:     if (list1.Any())

  10:     {

  11:         Console.WriteLine("if - any");

  12:     }

  13:  

  14:     Console.ReadLine();

  15: }

 

Wo liegt der Unterschied zwischen list1.Count und list1.Any? In erstem Fall wird die Liste durchiteriert, um herauszufinden, wie viele Elemente in der Liste sind. Bei Any wird nur geprüft, ob überhaupt ein Element in der Liste ist. Bei einer Prüfung > 0 ist also Any die bessere Wahl, weil die Liste nicht durchiteriert werden muss! Bei 100000 Elementen kann sich das durchaus lohnen…

image

%d Bloggern gefällt das: