Beeinflussung von AOP mit Attributen über IoC; Code-Geruch oder elegant?

8

Ich verwende StructureMap im Moment, im Allgemeinen mit konventioneller ( Scan() ) Autokonfiguration, und ich suche nach dekoratorbasiertem Caching in die Pipeline.

Wenn ich es manuell konfiguriere, ist das in Ordnung, aber Scan() ist nur so praktisch , wenn Sie viele Abhängigkeiten bekommen ... Ich spiele mit dem Hinweis auf Cache Vorschläge auf der / den Schnittstelle (n), zum Beispiel:

%Vor%

mit der Idee, dass durch Hinzufügen einer benutzerdefinierten "Konvention" zu StructureMap scanning (ziemlich einfach) erkennen kann, dass ein oder mehrere Methoden für das Zwischenspeichern eingerichtet sind, und injizieren automatisch einen generierten Caching-Decorator in das Typ-Pipeline (erzeugt einen Cache-Schlüssel aus dem Interface / Methodennamen und Parameterwerten).

Auf der positiven Seite macht es das Hinzufügen von Caching sehr schmerzlos - schmücken Sie einfach das Interface ein wenig; aber ist es ein Code-Geruch? Und / oder dupliziere ich etwas, das bereits gelöst ist?

    
Marc Gravell 10.02.2010, 08:06
quelle

7 Antworten

7

Attribute sind in Ordnung, wenn Sie zwei Hauptfaktoren kennen:

  • inhärent dezentralisierte Struktur, anstatt an einem Ort haben Sie Ihre Metadaten auf jede einzelne Komponente gesprengt

  • Starre Compiler konstante Struktur. Wenn Sie plötzlich entscheiden, dass Ihre Cache-Dauer 10, nicht 20 sein soll, müssen Sie Ihren gesamten Code neu kompilieren. Sie könnten Attribute zu Dingen wie config routen, aber das ist um die Attribute herum, und an diesem Punkt sollten Sie wirklich überdenken, ob die Verwendung von ihnen die beste Idee überhaupt war.

Solange Sie diese Probleme kennen und mit ihnen einverstanden sind, können Sie weitermachen.

    
Krzysztof Kozmic 10.02.2010, 08:21
quelle
5

Soweit ich die Frage verstehe, überlegen Sie hauptsächlich, die Attribute hinzuzufügen, um die Containerregistrierung zu vereinfachen. Sie implementieren die Caches immer noch mithilfe des Decorator-Entwurfsmusters, bei dem es sich um IMO handelt, die richtige Methode zum Implementieren von Caching.

Wir machen dasselbe in Safewhere, verwenden aber stattdessen die konventionsbasierte -Registrierung. Wir benutzen auch Castle Windsor, also weiß ich nicht, ob das mit StructureMap möglich ist, aber wir durchsuchen einfach die entsprechenden Assemblies nach dem Namen Caching*Repository und registrieren diese als Decorators für die echten Repositories. Wir haben auch einen Convention-basierten Komponententest, der überprüft, ob alle erforderlichen Caching-Repositories vorhanden sind.

Ob das Hinzufügen des benutzerdefinierten Attributs ein Code-Geruch ist oder nicht, hängt vom Grad der Wiederverwendbarkeit Ihres Codes ab. Meine Faustregel ist, dass ich fähig sein alles mit Poor Man's DI verbinden zu können. Ich benutze immer noch einen DI-Container, aber diese Regel bietet mir eine Plausibilitätsprüfung.

Im Allgemeinen mag ich es nicht, meinen Code mit einem bestimmten Container zu verbinden, aber ich kann nicht wirklich herausfinden, ob Sie das hier tun. Es hängt davon ab, ob Sie auf StructureMap verweisen müssen, um das benutzerdefinierte Attribut zu definieren. Wenn Sie Strukturkarte referenzieren müssen, würde ich es als einen Geruch betrachten.

    
Mark Seemann 10.02.2010 08:41
quelle
2

Der einzige Nachteil, den ich hier sehe, ist, dass es keine zentrale Stelle gibt, wo Objekte zwischengespeichert werden. Normalerweise gibt es eine bestimmte Ebene, auf der Caching durchgeführt wird. Mit Ihrer Technik ist dies nicht der Fall.

Ich denke auch, dass es die Verantwortung Ihres Codes ist zu entscheiden, ob etwas zwischengespeichert werden soll oder nicht, nicht das einer Klasse / Schnittstelle.

Aber um Ihre Frage zu beantworten, ist das ein Code-Geruch? Ich würde nein sagen, aber es könnte für neue Entwickler verwirrend sein, das System zu beherrschen, sobald es an vielen Orten verwendet wird.

    
Gerrie Schenck 10.02.2010 08:12
quelle
1

Ich kann nicht sagen, dass ich alles vollständig verstehe, aber für meine 2 Cent scheint es wohl okay zu sein; aber ich frage mich nur, ob es leicht ist, es ohne Neukompilierung zu ändern. Vielleicht möchten Sie diese Cache-Dauer über den Konfigurationseintrag und nicht über eine Kompilierung ändern. Ich würde diese Daten wahrscheinlich irgendwo speichern, wo ich sie einfacher konfigurieren kann. (Vielleicht habe ich aber missverstanden ...)

    
Noon Silk 10.02.2010 08:16
quelle
1

Ich stimme eher mit dem überein, was gesagt wurde, dass das Caching von Ihrem Code entschieden werden muss, aber ein anderes Szenario, das Sie vielleicht in Betracht ziehen möchten, ist das "Was muss zwischengespeichert werden, das gesamte Objekt?" p>

Vielleicht möchten Sie mit der Idee spielen, Eigenschaften zu haben, um festzulegen, welche Mitglieder Sie nicht von einem Objekt zwischenspeichern möchten.

Vielleicht ein Attribut

%Vor%

?

    
Pieter Germishuys 10.02.2010 08:24
quelle
1

Ich denke, dass man bei der Verwendung von Attributen immer daran denken sollte, die Absicht mit der Klasse zu verbinden. Der Punkt ist, dass Sie diese Entität nicht an einem einzigen Ort mit einer Cachedauer von 10 Sekunden und einem anderen Ort mit einer Cachedauer von 60 Sekunden verwenden können. IMHO ist das immer der Kompromiss mit Attributen jeglicher Art.

    
aaron 09.11.2010 01:49
quelle
1

Ich bin ein bisschen zu spät zur Party, aber ich habe in letzter Zeit über dieses Problem nachgedacht, und ist das Verwenden von Attributen zum Caching ein Code-Geruch .

Hier sind ein paar Gründe warum:

  1. Caching nach Attributen kann Sie in ein "Schwanz-wackeln-den-Hund" -Szenario versetzen, da es das Potenzial hat, das Design Ihres Codes zu ändern, wenn Sie Methoden implementieren, die sich dafür eignen das Caching-Attribut, besonders wenn Sie in komplexe Szenarien geraten.

  2. Das Caching nach Attribut ist gefährlich, da der Vorgang des Hinzufügens von Elementen zum Cache im Allgemeinen derselbe ist (dh cache.Add (Schlüssel, Wert)), der Prozess des Ermittelns des Schlüssels und des einzufügenden Elements ist nicht immer gleich und erfordert normalerweise eine Art von Logik, die nicht immer generisch ist. Zum Beispiel wird oft daran gedacht, den Cache-Schlüssel mithilfe der Parameterwerte zu generieren, aber berücksichtigen Sie das Szenario, in dem ein DateTime-Parameter verwendet wird und der Aufrufer DateTime.Now übergibt ... der Rückgabewert könnte immer derselbe sein, aber Der Schlüssel, der von den Parametern generiert wird, ist unterschiedlich und generiert für jeden Aufruf ein neues Cache-Objekt. Sie könnten dann das Design der Methode ändern, aber dann bekommen Sie genau das Problem beschrieben in 1

  3. Im Allgemeinen wird Caching verwendet, um ein bestimmtes Szenario zu optimieren, und es ist selten, dass der Grund -Eintrag im Cache identisch ist. Angenommen, Sie haben einen Katalog von Elementen, die sich selten ändern. Sie könnten den gesamten Katalog beim Start der Anwendung in den Cache laden und ihn für 12 Stunden zwischenspeichern, aber Sie könnten die Benutzerdetails eines Benutzers nur speichern, nachdem sie sich angemeldet haben das erste Mal. Die Logik, die erforderlich ist, um diese Elemente abzurufen und sie dann einem Cache hinzuzufügen, ist völlig anders und eignet sich nicht dazu, in einem Attribut erfasst zu werden.

  4. Wenn Sie ein Cache-Attribut hätten, müssten Sie auch Cache-Elemente verfallen lassen, wenn sie sich ändern. Unter der Annahme, dass Sie ein Cache-Attribut haben, hätten Sie höchstwahrscheinlich ein "CacheExpiry" -Attribut, das die gleichen Probleme hätte, aber Sie müssten dann auch eine allgemeine Methode zum Generieren von Cache-Schlüsseln zwischen Methoden entwickeln Es ist sehr unwahrscheinlich, dass Ihre Parameter zum Aktualisieren oder Löschen eines Objekts dieselben sind wie beim Hinzufügen eines Objekts zum Cache.

Unterm Strich ist Caching nach Attribut auf der Oberfläche eine gute Idee, aber in der Praxis bedeutet die Art der Probleme, die Caching löst, dass es sich nicht gut dazu eignet, von Attributen gesteuert zu werden.

    
lomaxx 15.05.2011 23:46
quelle