Laden...
Avatar #avatar-3206.png
Benutzerbeschreibung
„Morgen ist noch nicht gekommen, und gestern ist vorbei. Wir leben heute.”

Forenbeiträge von malignate Ingesamt 742 Beiträge

23.09.2014 - 23:02 Uhr

@Sebastian.Lange: Sehe ich komplett anderst: Das ist eine Klasse, die für die Serialisierung gedacht ist (und um vll. daraus Metadaten zu erzeugen). Und diesen Zweck und keinen anderen sollte die Klasse optimal erfüllen. Optimal heißt auch immer einfach und simpel. Wenn ich jetzt einen sehr schnellen Serializier mit tollen Feature hätte, der nur Felder lesen und schreiben kann, dann würde ich aus den Properties eben Felder machen, das spielt hier absolut keine Rolle.

Jeder, der will kann das Array überschreiben ist für mich hier kein besonders starkes Argument, weil die Klasse eben eh niemand zu Gesicht bekommt (bzw. Objekte dieser Klasse). Man bekommt eine Instanz von WCF oder aus einem Stream und erzeugt daraus ein Business-Objekt. Du könntest meiner Meinung nach hier auch Felder aus allen Properties machen. Das macht die Klasse nicht wirklich schlechter, die Kapselung durch Properties ist ja hier eh nur theoretisch.

23.09.2014 - 22:19 Uhr

Diese Contract-Klassen sind ja nur zum Serialisieren. Die haben mit OOP/Objektorientiertem Design auch nur bedingt was zu tun, sondern sind einfach Datenstrukturen. Deshalb finde ich es hier vollkommen legitim die Warnung zu deaktivieren. Stichwort: KISS

Man darf bloß nicht den Fehler machen, weiter damit zu arbeiten. Du solltest die Instanzen dieser Klasse dann am besten in Business-Objekte konvertieren.

23.09.2014 - 18:01 Uhr

Wieso deaktivierst du es nicht einfach für diesen speziellen Fall?

22.09.2014 - 15:12 Uhr

Das ist mir schon klar, so viel Isolierung brauche ich gar nicht, dafür gibts ja Test-Umgebungen. Das wäre zwar schön, aber dafür ist mir der Aufwand zu hoch im Moment. Mir gehts nur um die letzten 10 Minuten vor Deployment mit Live-Daten.

Ich bin mir gerade nicht sicher, wie das bei Azure ist. Wenn ich das gerade richtig in Erinnerung habe, ist es bei Azure Websites so, dass dort das Staging nichts extra kostet, bei Web Roles verdoppeln sich die Kosten (wenn man nicht irgendwie clever hoch- und runter fährt). Ich gehe deshalb davon aus, dass bei Websites die gleichen Resourcen mitgenutzt werden. Evtl. kriege ich die Loadbalancer-Leute dazu, das für mich ein Url-Rewriting einzurichten, z.B. von staging.site.de auf site01.site.de etc.

22.09.2014 - 11:09 Uhr

Ja, das Problem dabei ist, dass ich nur begrenzt Kontrolle über den LB habe. Deshalb die Idee, das Binding zu swappen. Dann hat man zwar keine 0-Downtime, aber besser als ohne.

Das geht auch über die WebAdministration-Tools für .NET, man muss dazu aber:

  1. Alle Bindings löschen, dann Commit
  2. Kurz warten
  3. Alle Bindings neu setzen, dann Commit

Dann kommt der IIS aber je nach Timing durcheinander und stoppt die Webseite, was ziemlich nervig ist. Deshalb muss man sich dann entweder Remote oder über einen Agent auf jedem Server neu mit dem IIS verbinden und die Seite starten. Das ganze geht relativ schnell (2,3 Sek), ist aber aufwändiger als gedacht. Deshalb habe ich auf eine einfache Lösung gehofft.

22.09.2014 - 10:34 Uhr

Ich dachte das wurde eingesellt, bzw. nur für IIS 7 verfügbar.

22.09.2014 - 10:13 Uhr

Hi zusammen,

wir sind wieder von Azure auf eigene gewechselt, weil mir die Preis-Leisung einfach nicht zugesagt hat und der VerwaltungsaufwandServer bei Azure doch höher war als gedacht. Wie auch immer, das einzige Feature, das ich vermisse, ist das Staging. Das bedeutet, man stellt 2 Webseiten mit der gleichen Konfiguration zur Verfügung, deployment auf die Staging Umgebung und fährt die Webseite hoch und tauscht dann Staging mit Production.

Hat jemand eine Idee, wie man das nachbilden kann? wir haben 3 Server die per Shared Configuration und DFS synchronisiert werden. Man könnte für das Staging beispielsweise 2 Webseiten anlegen und das Binding und den Namen der Seiten swappen (dann bleibt der App-Pool gleich!). Allerdings muss das in der richtigen Reihenfolge und relativ unmittelbar passieren, weshalb man wohl 3 Agents laufen lassen müsste. Den Namen der Seite im IIS muss wegem Web Deployment geändert werden.

Der Loadbalancer ist gemanaged, evtl. könnte man hier auch ein Swapping einrichten. Dann müsste nur der Namen der Webseite geändert werden, was weniger kritisch als das Binding ist. Evtl. kann man auch eine Dummy-Webseite für das Web-Deployment anlegen, die immer auf das Staging-Verzeichnis weist.

Würde mich über eine Idee freuen.

17.09.2014 - 11:51 Uhr

Du hast noch gar nicht erklärt, wieso das so effektiv sein soll. Falls 32 bit für dich ausreichen und du eine gute Bibliothek für PNGs hast, würde ich dabei bleiben. Das ist ein sehr kompaktes Format mit Kompression und Filter, die auch noch einiges an Platz sparen. Ob du jetzt was aus dem Bild erkennen kannst, ist meiner Meinung nach egal, in der Grafikprogrammierung werden Texturen ja auch zu mehr verwendet. Das arbeiten auf Byte-Ebene empfinde ich in C# manchesmal als sehr nervig und man muss extrem aufpassen, was man tut. Das Potential in Bezug auf Lesegeschwindigkeit was "kaputt" zu machen ist sehr groß.

17.09.2014 - 10:43 Uhr

Hallo,

ich finde die Diskussion entgleitet ein bisschen:

Aufwand: Die Frage ist nicht entscheidend, sondern vielmehr wo meine Prioritäten liegen und was mir den größten Nutzen bringt. In einem Szenario ist es die perfekte UI/UX mit wenigen Features in einem anderen Szenario vielleicht viele Features, mit einer eher funktionalen Oberfläche. Hierbei macht ein kleines Feature wie der Overlay aber nicht den großen Unterschied, sondern eher der Gesamteindruck für den Benutzer.

Externe Resourcen: Möchte man z.B. im Web eine Datei hochladen ist man eben teilweise auf die Dialoge angewiesen, wie sie der Browser implementiert. Die sind nun mal modal, da führt kein Weg daran vorbei. Man kann und sollte vielleicht auch alert und confirm-Boxen verwenden. Hier gibt es mittlerweile ja viele schöne, alternative Lösungen.

Die Diskussion ist aber zu abstrakt und lässt sich nur für bestimmte Szenarien wirklich durchdiskutieren. Da ist die Diskussion auch ein bisschen vom Titel abgewichen. Im Prinzip geht das Thema auch noch viel weiter, ein Beispiel wäre vielleicht auch die Speichern-Ansicht in Office, die zwar kein modaler Dialog ist, aber ähnliche Nachteile hat.

17.09.2014 - 09:47 Uhr

@Mallett:

Es gibt Szenarien und Produkte, wo Usability ein wichtiges oder sehr wichtiges Verkaufskriterium ist. Beispielsweise Task-Management-Tools, evtl. Entwickler-Werkzeuge usw. Das kommt natürlich darauf an, wie man sich von anderen Produkten differenzieren kann und wie die Prioritäten liegen.

Und dann spielt es einfach keine Rolle, ob man 10 Minuten Arbeit einsparen kann. Hier zahlt sich jeder Mehraufwand direkt durch eine höhere Kundenzufriedenheit aus. Auf der anderen Seite gibt es natürlich viele B2B-Lösungen, die einfach runterentwickelt werden, die keine Konkurrenz haben oder wo die Feature-Menge entscheidend ist. Das dann wenig Zeit für UI und Usability eingeräumt wird, ist nur logisch.

Die Praxis ist also sehr unterschiedlich.

Btw: Ich glaube in WPF ist der Aufwand eine MessageBox anzuzeigen höher als eine alternative Lösung, weil ich hier mehr Aufwand treiben muss, um die MessageBox für Tests zu mocken.

15.09.2014 - 22:21 Uhr

Du hast ein paar offensichtliche, logische Fehler und Fehler in der Syntax:

  1. Ein Figur ist die Basis-Klasse für alle 2D-Objekte und da fällt mir keine Eigenschaften ein, die alle Felder gemeinsam haben. Ein Kreis hätte ein Radius, ein Rechteck eben 2 Seitenlängen und ein Quadrat nur eine Seitenlänge. Was aber alle Klassen gemeinsam haben ist die Möglichkeit, die Fläche zu berechnen.
  2. int flrecht hat nichts im Konstruktor zu suchen.
  3. Falls kein anderer Konstruktor definiert ist, hat eine Klasse immer den Standard-Konstruktor ohne Parameter, deshalb wird der Aufruf base(a, b) auch nicht funktionieren.
  4. int flrecht ist in "FlächeRechtecckBerechnen" ein Ergebnis, kein Argument. Mache deshalb ein Rückgabewert draus.
  5. Methoden sollten mit einem Verb beginnen "BerechneFlaeche"

Dein Beispiel könnte Korrekt so aussehen:


abstract class Figur
{
   public abstract int BechneFlaeche(); // Auch abstrakt, Methode MUSS implementiert werden.
}

class Rechteck : Figur
{
   private int a, b;
   public Rechteck(int a, int b)
   {
      this.a = a;
      this.b = b;
   }

   public override int BerechneFlaeche()
   {
       return a * b;
   }
}

class Quadrat: Figur
{
   private int a;
   public Quadrat(int a)
   {
      this.a = a;
   }

   public override int BerechneFlaeche()
   {
       return a * a;
   }
}

Alternative könnte man Quadrat auch so definieren:


class Quadrat: Rechteck // Ein Quadrat IST ein Recheck
{
   public Quadrat(int a)
     : base(a, a) 
   {
   }
}

29.08.2014 - 12:29 Uhr

Was heißt viele Objekte und was bedeutet Thread-Pool in dem Zusammenhang?

13.08.2014 - 21:46 Uhr

Warum musst du warten? Im Prinzip musst du doch nur irgendeine Lade-Animation anzeigen und wenn die Nachricht eintrifft, deine UI aktualisieren.

13.08.2014 - 11:09 Uhr

Oder du erstellst dir eine EBNF und generierst einen Parser, z.B. mit Grammatica (http://grammatica.percederberg.net/).

23.07.2014 - 13:52 Uhr

Mal danach gesucht? Gibt einige Beispiele dafür und Delegates sind (erweiterte) Grundlagen. Durch die Details musst du dich auch selber ein bisschen kämpfen.

23.07.2014 - 11:48 Uhr

OWIN verwendet einen CookieAuthenticationProvider (CookieAuthenticationProvider Class). Du kannst über das Property OnValidateIdentity ein Delegate mit der Validierungslogik hinterlegen. Dort musst du überprüfen, ob du dein Benutzer noch gültig ist, also zum Beispiel in einer Datenbank steht.

22.07.2014 - 19:28 Uhr

Variante 3:

OWIN verschlüsselt Cookies im IIS über den MachineKey. Das kann man überschreiben.
Customize the cookie value in MVC5 ASP.NET Identity

Wenn du den Key überschreibst und einfach neu generierst, kannst du eine Logout ebenfalls erzwingen. Dafür brauchst nicht mal eine DB.

Falls Owin den Cookie nicht jedes mal überprüft, kann man das zumindest einstellen (bin mir da nicht so sicher gerade).

14.07.2014 - 15:31 Uhr

Sorry, mein Fehler.

Aber das sind doch jetzt wirklich Grundlagen. Schau dir das Beispiel in MSDN nochmal an, da gibts ein 1:1 Zusammenhang zwischen dem Typ der Expression und dem Typ der Function (Func).

14.07.2014 - 15:14 Uhr

Func<object> test=expression.Compile();

14.07.2014 - 15:13 Uhr

Hast du es mal mit einem existierenden Grid probiert? z.B. von Telerik

http://www.telerik.com/products/wpf/overview.aspx

14.07.2014 - 14:44 Uhr

Ich kenne keinen HTML-Editor. Was ich schon gemacht habe:

  1. Telerik-Reporting, klappt ganz gut.

  2. http://wkhtmltopdf.org/. Einfach ein HTML-Seite mit dem Report erstellen und daraus dann ein PDF generieren. Klappt für einfache Sachen auch ausgezeichnet und kostet nix.

14.07.2014 - 14:37 Uhr

Ich übersehe vll. etwas, aber warum nimmst du nicht einfach die Compile-Methode?

Expression<TDelegate>.Compile Method

14.07.2014 - 14:34 Uhr

Müssen die wirklich alle unterschiedlich groß sein? Das bricht dir nämlich hier das Genick. Wenn die Spalten und Zeilen jeweils unterschiedlich sind kannst du das noch vorberechnen. Dann sind es nur noch 300+300 Größen, die du wisssen musst.

In Kombination mit Virtualizing (Implementing a VirtualizingWrapPanel) könntest du dann die entsprechenden Bereiche einfach auswählen.

14.07.2014 - 11:41 Uhr

Im MVVM-Light-Framework gibt es ein MessageBus mit dem ViewModels Daten hin und herschicken und über Änderungen informieren. Ich habe seit bestimmt 2 Jahren nichts mehr mit XAML gemacht, aber ich fand das Konzept recht cool:

http://chriskoenig.net/2010/07/05/mvvm-light-messaging/

08.07.2014 - 17:06 Uhr

Mal in die Konsole im Browser geschaut? Glaube F12 in Chrome und IE

08.07.2014 - 10:01 Uhr

Ich glaube DefaultValue klappt nur bei der Serialisierung, ist aber nur eine vage Vermutung.

08.07.2014 - 09:59 Uhr

Hast du es schonmal mit einem manuellen Stream-Flush probiert?

07.07.2014 - 21:49 Uhr

Nice, ich finds gut.

Habe zwei Wünsche:

  1. Mach ein NuGet Packet draus
  2. Packe noch eine globale Einstellung dazu, damit ich es es im Debug-Modus etc. global deaktivieren kann. Statisches Property oder AppSetting würde mir reichen.

Btw: Dein PerformanceMessureFilter ist nicht für parallele Requests geeignet 😉

05.07.2014 - 15:33 Uhr

Da sagt der MSDN-Link aber was anderes 😉

05.07.2014 - 10:28 Uhr

@Herbivore: Zugegeben die kürzeste mögliche Antwort, aber schau mal in die erste Antwort von mir. String.Join im System-Namespace 😉

04.07.2014 - 17:44 Uhr

Der Serializer deserialisiert, nur wenn auch wirklich vorhanden, probiers doch aus:


public class Program
    {
        public class Container
        {
            [XmlElement("Item")]
            public List<Item> Items { get; set; }
        }

        public class Item
        {
            public bool Flag { get; set; }

            public Item()
            {
                Flag = true;
            }
        }

        static void Main(string[] args)
        {
            string xml = @"<Container><Item /><Item /></Container>";

            StringReader reader = new StringReader(xml);

            XmlSerializer serializer = new XmlSerializer(typeof(Container));

            Container container = (Container)serializer.Deserialize(reader);

            foreach (var item in container.Items)
            {
                Console.WriteLine(item.Flag);
            }
        }
    }

04.07.2014 - 15:31 Uhr

Setzt das Flag doch einfach im Konstruktor auf true

25.06.2014 - 17:53 Uhr

Du kannst Aufzählungen auch anders realisieren: Enumeration classes

22.06.2014 - 14:38 Uhr

So wie ich das verstehe funktioniert es doch so:

  1. Client bildet seine Hashs und übergibt die an Server
  2. Server ermittelt, welche Daten er benötigt und schicke Aufforderung an Client
  3. Client sendet (partielle) Daten

Das heißt die Datenmenge ist maximal Daten + Hashes, jetzt kommt es aber auf das genaue Szenario an. Da der Thread-Ersteller hier von Kopieren und Synchronisieren gesprochen hat, weiß ich nicht, ob es was bringt. Will er Kopieren hat rsync in der Tat keine Vorteile (aber auch keine großen Nachteile, die Hashs dürften nicht so groß werden), geht es auch um Synchronisieren hat rsync sehr viele Vorteile.

Je nachdem wie gut der Wrapper ist, hat er mit einer halben Stunde Konfigurationsaufwand rsync auch eingerichtet.

21.06.2014 - 15:56 Uhr

Ich habe keine wirklich Ahnung von rsync, hatte nur mal gelesen, dass rsync, bzw. eine Weiterentwicklung auch für Dropbox eingesetzt wird.

So wie ich das verstehe handeln Client und Server über Hashs aus, was gesendet werden soll und senden dann. Die Übertragungsmenge ist dann maximal Daten+Hashs. Wie gesagt, habe ich mich aber auch nicht im Detail damit beschäftigt, wollte es aber mal in den Raum werfen, damit sich der Thread-Ersteller evtl. näher damit beschäftigen kann.

05.06.2014 - 10:07 Uhr

Ich meinte eher Topics. Hierbei kannst du glaube ich pro Subscription ein Filter angeben.

Bei so spärlichen Informationen wird dir hier aber eh keiner helfen können.

05.06.2014 - 08:54 Uhr

Ich würde mal über ServiceBus nachdenken, den finde ich für sowas deutlich angenehmer.

02.06.2014 - 18:47 Uhr

Das ganze ist nicht so einfacher. Vll. kann NuGet sogar helfen, daran hätte ich jetzt spontan nicht gedacht, aber du musst eine ganze Reihe von weiteren Problemen lösen, insbesondere, wenn du Plugins zur Laufzeit ohne Neustart laden möchtest.

  1. Wie kannst du dynamische Routen registrieren? Relativ leicht geht das mit Attributen.
  2. Wie machst du Views zur Laufzeit bekannt? Hier könnte dir evtl. das Caching einen Streich spielen.
  3. Möchtest du Plugins auch wieder entladen?
  4. Wie melden Views Anforderungen an Skripte und Styles an, gibt es hier ein automatisches Bundling?
  5. Funktioniert Razor-Intellisense auch für Plugins (das ist echt ein nerviges Thema).
  6. Sollen Plugins isoliert ablaufen oder nicht?
  7. ...

Also einfach wird es nicht, es ist aber auch nicht unlösbar.

Ich würde dir empfehlen, dir das Orchard-CMS anzuschauen. Die Usability ist meiner Meinung nach grausam aber man kann trotzdem einiges daraus lernen.

14.05.2014 - 11:17 Uhr

Wenn du genauso schnell arbeiten und deine Kosten für Wartung und Pflege von Code auch noch geringer sind, nix dagegen. Allerdings würde ich allgemein solche Kosten im Cent-Bereich gegen 30€-50€ Stundenlohn eines Entwicklers gegenrechnen. Angenommen eine L-Instanz bei Azure kann die Attribute-Validation in 1ms durchführen, dann kannst du 660 Mio Validierungen durchführen, bis 50€ erreicht sind (falls ich mich nicht verrechnet habe)

14.05.2014 - 10:18 Uhr

Ich kann deine Kritik ja teilweisen nachvollziehen, aber wenn du sowas in den Raum schmeißt, solltest du es auch begründen:

  1. Jede Abstraktion ist irgendwie langsamer, das ist ja klar, aber Validation-Attribute verlangen ja nicht bei jedem Aufruf Reflection (kommt drauf an, ich weiß). Weviel langsamer also als es manuell zu machen und in welchem Verhältnis zum Gesamtrequest? 1ms ist doppelt so lange wie 0,5ms, aber bei einem Request von 200ms immer noch voll vertretbar in den meisten Fällen.

  2. Unflexibel: Ja, manche Sachen sind unflexibel, zum Beispiel sowas wie das CompareAttribute. Aber bisher waren das bei mir nur extreme Ausnahmen, wo mich das wirklich gestört hat. Wie ist hier die Realtität aber wirklich?

Als Alternative kann ich mal noch Fluent Validation in Raum werfen: http://fluentvalidation.codeplex.com/

14.05.2014 - 09:07 Uhr

Das Tutorial sieht gut aus auf den ersten Blick, hier ein paar Anmerkungen:

  1. Nimm doch einfach das Attribute für Reguläre Ausdrücke

  2. Du kannst Client Validation auch mit dieser Klasse implementieren: DataAnnotationsModelValidator-Klasse, Vorteil: Dein Attribute muss von ASP.NET MVC nichts wissen.

  3. Wieso definiert du ErrorMessageResourceType und ErrorMessageResourceName nochmal neu, die kommen doch von der Basisklasse.

  4. In den meisten Fällen reicht es aus, diese Methoed zu überschreiben: ValidationAttribute.IsValid-Methode (Object)

13.05.2014 - 20:53 Uhr

@Herbivore:

Man kann ContinueWith ja einfach hintereinanderkettern, da ContinueWith ein Task zurückliefert, der die angehängte Aufgabe repräsentiert.


static void Main(string[] args)
{
    string result =
        Task.Run<int>(() => Test1())
            .ContinueWith<int>(x => Test2(x.Result))
            .ContinueWith<string>(x => Test3(x.Result)).Result;

    Console.WriteLine(result);
    Console.Read();
}

public static int Test1()
{
    return 1;
}

public static int Test2(int x)
{
    return x + 1;
}

public static string Test3(int x)
{
    return "Hello" + x;
}

Das liefert nämlich das gewünschte Ergebnis: Nämlich Hello2

Da aber in unserem Async-Szenario ein im ContinueWith wieder ein neuer Task erstellt wird, müssen wir aus einem Task<Task> ein Task erstellen, damit wir mit dem weiteren Ablauf fortfahrten können, wenn der innere Task fertig ist und nicht der äußere. Die Implementierung ist ein bisschen tricky, in Mono ist es aber einfacher zu verstehen:

github / mono / mcs / class / corlib / System.Threading.Tasks / TaskExtensionsImpl.cs

Wahrscheinlich ist hier aber eine State-Machine sogar einfacher 😉

13.05.2014 - 18:54 Uhr

@Herbivore:

13.05.2014 - 16:01 Uhr

Du kannst doch auch einfach eine asynchrone Methode anbieten, die intern mit async und await arbeitet:


public async Task LoginAnDoAsync()
{
 await InitializeAsync();
 await LoginAsync();
 await StartAsync();
 await UninitializeAsync();
}

Man kann bei sowas noch Performance sparen, indem man die Verkettung von Tasks einfach selber macht:


public async Task LoginAnDoAsync()
{
    return InitializeAsync()
        .ContinueWith(x => LoginAsync())
        .ContinueWith(x => StartAsync())
        .ContinueWith(x => UninitializeAsync());
}

Der Compiler muss nun keine State-Machine mehr generieren.

Man muss aber aufpassen, weil dadurch ein Teil der Arbeit wieder in einen deiner Haupt-Threads verlagert wird, zum Beispiel der UI-Thread.

13.05.2014 - 10:19 Uhr

Ich habe die Erfahrung gemacht, dass ein statischer Service-Locator fürs Testen sehr nerven kann. Ich glaube in meinem Szenario wurden die Tests parallel ausgeführt und da zwei Testklassen unterschiedliche Mock-Objekte verwendet haben, sind diese dabei durcheinander gekommen. Deshalb ist meine Präferenz im Moment Variante 4.

Die Begründung gegen Service-Locators lautet ja oft, dass hier Infrastruktur-Code in Klassen steht, die eigentlich nichts damit zu tun haben. Eventuell lässt sich das mit eine BusinessObject Basisklasse aber reduzieren.

13.05.2014 - 07:43 Uhr

Danke für das Feedback. Ich habe meinen Post systematischer gemacht und mal alle Punkte aufgezählt, die mir spontan einfallen. Bisher gefällt mir Alternative 4 am besten.

12.05.2014 - 23:19 Uhr

Hallo zusammen,

ich weiß, das Thema hat Potential zu Grundsatzdiskussionen, aber ich frage trotzdem einfach mal: Ich habe bisher viel mit Dependency-Injection und Entitäten gearbeitet, aber erkannt, dass meine Architektur sehr einem nicht-OOP-Design ähnelt, bei dem zustandslose Services Strukturen (Entitäten) bearbeiten. Wahrscheinlich könnte man viel Code auch ohne Probleme mit C lösen. Sprich, es war eine Anämisches Domänenmodell. Deshalb möchte ich meien zukünfigten Projekte, sofern sie keine sehr speziellen Anforderungen bezüglich Performance oder anderen Belangen haben, vermehrt mit Rich Domain Models realisieren. Dabei kann man natürlich nicht alle Belange in den Geschäftsmodellen realisieren, sondern wird nicht darum herum kommen, auch externe Dienste zu injezieren, beispielsweise ein IMailService.

Dabei stelle ich mir die Frage, wie solche Services injeziert werden. Folgende Varianten sind zum Beispiel denkbar.

  1. Constructor Injection: Die Klasse, die das Geschäftsmodell erstellt, zum Beispiel ein Repository, oder eine Factory, injeziert alle Abhängigkeiten über den Konstruktor entweder selbst oder über einen DI-Container.
  • Alle Services im BO immer vorhanden
  • Einfache Verwaltung von Services
  • Services werden kontextabhängig verwendet und nicht immer benötigt, Lazy Loading wird aber teilweise von DI-Containern unterstützt
  • Repository muss sich darum kümmern.
  • Eventuell ein sehr langer Konstruktor
  • Eventuell Performance-Probleme bei vielen Objekten
    => Gefahr zu groß, dass Konstruktor riesig wird
  1. Double Dispatching: Einer Methode werden alle Abhängigkeiten direkt übergeben.
  • Abhängigkeiten einer Methode klar erkennbar
  • Viele Parameter bei komplexen Prozessen
  • Viele Parameter am Anfang einer Aufrufskette
  • Verschleiern des Geschäftsinformationen
  • Aufwändige Verwaltung der Services beim Aufrufer
    => Ungeeignet, kann aber mit anderen Methoden kombiniert werden
  1. Service Locator: Eine Art globale, statische Factory liefert Services aus.
  • Einfache Methoden und Konstruktor im Business Objekt
  • Eigene Verwaltung von Services möglich
  • Lazy-Loading
  • Verwantwortung über Services beim Business Object
  • Statische Methoden schwierig, wenn Tests parallel ausgeführt werden
    => Statische Methoden zu problematisch
  1. Service Locator injeziert: Jedem Business Objekt wird ein Service-Locator injeziert, über welchen bequem alle Services abgefragt werden können.
  • Einfache Methoden und Konstruktor im Business Objekt
  • Eigene Verwaltung von Services möglich
  • Lazy-Loading
  • Sehr einfach zu testen, zum Beispel mit abstrakter Basisklasse für Service Locator
  • Verantwortung über Injektion beim Repository
  • Verwantwortung über Services beim Business Object
    => Viele Vorteile, bisher am vielversprechendsten
  1. Komplette Vermeidung: Neigt evtl. wieder zu einem anämischen Geschäfstsmodell.

Bisher gefallt mir keine Alternative richtig gut, Alternative 4 scheint mir die wenigsten Nachteile zu haben. Wie löst ihr das Problem, sehr ihr weitere Möglichkeiten?

07.05.2014 - 00:30 Uhr

Zum Thema Architektur kann ich noch zwei gute Blogs empfehlen:

  1. http://ayende.com/blog/
  2. http://codebetter.com/gregyoung

Allgemein würde ich mich an ein paar grundlegende Prinzipien halten, der Rest ergibt sich dann schon selbst:

  1. KISS: Favorisiere einfache Lösungen
  2. SoC: Separation of Concerns: Fasse keine verschiedenen Belange in einer Einheit (z.B. Klasse zusammen)
  3. DRY: Wiederhole dich nicht
  4. Schreibe testbaren Code (passiert durch SoC fasst automatisch)
  5. Bleibe nahe an der Domäne: Abstrahiere nicht zu sehr, sondern verwende nahe Begriffe und Modelle, die zur Domäne passen.
  6. Besinne dich abundzu auf Objektorientiertes Design zurück (Stichwort: Business Objects).