| 

.NET C# Java Javascript Exception

4
Ich will mich mit Event-Based-Component's in C# beschäftigen. Habe aber noch Probleme mit dem Entwurf der In und Out-Pin's ;)

Ich will anfangen mit einer simplen Logging Komponente die ich eigentlich in jeder Anwendung gebrauchen kann. Also die Idee ist das ich eine austauschbare Komponente habe die einen String an verschiedene Ausgaben loggt. Console, File, Log-Server, ...

Da EBC's noch eine recht junge Methodik ist fehlen natürlich noch Best-Practices. Deswegen wollte ich von hier einfach mal ein Meinungsbild abfragen, wie ihr das angegehn würdet.

Hat eine Logging Komponente nur einen In-Pin ( z.B. In_Log(string) ) oder zusätzlich einen Out-Pin um das logging zu kascadieren? Wenn eine andere Komponente (z.B. Cache-Komponente) was loggen möchte biete ich ihr einen Out-Pin event Action<string> Out_Logging an, soweit verstanden. Annahme ich möchte dem Cache sowohl in die Console als auch in ein File loggen würde ich dann bei der Verdrahtung eher sagen :
a)
aCache.Out_Logging += aFileLogger.In_Log;
aCache.Out_Logging += aConsoleLogger.In_Log;


b)
alternativ könnte ich mir vorstellen das ich einen Multicast Logger Komponente die selbst einen Out-Pin besitzt einführe :

aMulticastLogger.Out_Logging += aFileLogger.In_Log;
aMutlicastLogger.Out_Logging += aConsoleLogger.In_Log;
aCache.Out_Logging += aMulticastLogger.In_Log;


c)
auch denkbar wäre das eine Logging Komponente immer auch einen Out Pin besitzt und ich dann sowas hätte :
aCache.Out_Logging += aFileLogger.In_Log;
aFileLogger.Out_Logging += aConsoleLogger.In_Log;


Die Lösung a) bedingt viel Verdrahtungsaufwand, b) delegiert den Aufwand auf eine Zwischenebene und c) stellt einen Pipe Mechanismus dar. Evtl. gibt es aber auch noch eine ganz andere Rangehensweise die mir noch nicht in den Kopf gekommen ist.

Wenn ich jetzt theroetisch eine Komponente habe die einen String in GROSSBUCHSTABEN wandelt und ich vorhabe alle Log Ausgaben in Großbuchstaben zu wandeln würde ich am besten mit der Lösung b) fahren und der aMultiCast Komponente das Großwandeln beibringen oder würde ich einfach zwischen der Cache Komponente und dem Multicast schalten als eine Art Transformation ?
aCache.Out_Logging += aUpcaseLogger.In_Log;
aUpcaseLogger.Out_Logging += aMulticastLogger.In_Log;


hier stört mich das die Komponente ja eigentlich nichts mit logging zu tun hat sondern mit Großwandlung eines Strings :(

Geht es eigentlich nur mir so das ich bei dem Thema EBC so viele Fragen habe ?
News:
17.05.2011
stefc 268 1 6
6 Antworten
4
Logging ist ein Aspekt, eine nicht-funktionale Anforderung. Wenn du die in einem Flow unterbringen willst, dann am besten als "Zwischenstück". Hier habe ich mal darüber unter dem Beriff Verbindungsstücke geschrieben.

Ob ein Cache oder andere Funktionseinheiten einen speziellen Log-Outpin haben sollten, weiß ich nicht. Solange du es vermeiden kannst, würd ich drauf verzichten.

Alternativ kannst du einen Logger als Abhängigkeit betrachten und entweder so explizit im Modell zeigen - oder rauslassen, weil er halt überall gebraucht wird.

Einen Multicast-Logger brauchts auf keinen Fall, würd ich sagen.

Insgesamt musst du aber aufpassen: du kommst von der Technik und nicht vom Anwendungsfall. Du versuchst, einen Framework auf der grünen Wiese zu entwerfen und hast keine Ahnung, ob und wie die Szenarien aussehen, in denen du ihn brauchst.

Ich denke, du solltest anders herum vorgehen. Nimm dir eben keine Infrastruktur als Übungsbeispiel, sondern eine Anwendung. Irgendwas kleines wie eine ToDo Verwaltung oder ein Spiel oder so. Das fokussiert dich darauf, Flows zu bauen, statt zu überlegen, wo du etwas in noch nicht existierende Flows einhängst.

Viel Spaß mit FD und EBC!

Ralf
18.05.2011
Ralf Westphal 765 1 4
Du hast recht mit nicht funktionalen Anforderungen zu starten ist evtl. keine gute Vorgehensweise. Allerdings will ich auch ein wenig verproben wie eine herkömliche Anwendung, schrittweise mit Refactoring in Richtung EBC sich entwickelt und da lag es für mich nahe sich mit solchen Aspekten wie Logging, Caching zu beschäftigen weil diese wie schon gesagt in den meisten Anwendungen immer wieder vorkommen. Wenn man sich hierfür aus einem Pool von per Interface Standardisierten EBC's einfach bedienen könnte würde es die Sache stark vereinfachen. Danke für deine Antwort und das Thema EBC !!
stefc 18.05.2011
+1
Ist es nicht so, dass ich mit einem als Abhängigkeit dargestellten Logger (vor allem) loggen würde, was innerhalb eines Bausteins passiert, während ein Verbindungsstück nur das loggen kann, was durch die Pins fließt? Wobei letzteres in einem guten Flow Design vermutlich das interessantere sein dürfte, oder?
Matthias Hlawatsch 18.05.2011
3
Dazu ein paar Nachtgedanken von mir, zuvor aber ein Disclaimer: ich habe mich mit Event Based Components bzw. Flow Designs bislang (leider) ausschließlich theoretisch beschäftigt anhand der Artikel von Ralf Westphal in der dotnetpro.

  • Was ist das Ziel Deines Unterfangens? Willst Du Dich vor allem mit EBCs beschäftigen, oder ist es Dir auch wichtig, am Ende ein solides Ergebnis zu haben, das weiterverwendet werden soll? Falls letzteres: unterschätze die Komplexität nicht und überleg Dir, ob Du nicht mit einer Fertiglösung wie log4net besser fährst.
  • Bei einer Logging-Komponente ist es m.E. besonders wichtig, zwischen Konfiguration und Nutzung zu unterscheiden. Letztere sollte so einfach wie möglich sein, schließlich zieht sie sich durch den gesamten Code. log4net.ILog halte ich für ein gelungenes Beispiel, wie eine solche Nutzersicht aussehen kann. Was dann mit den Logging-Informationen passiert, wie sie gefiltert und ausgegeben werden, ist Sache der Konfiguration und geht die nutzenden Komponenten nichts an.
  • Aus meiner Sicht wäre im Flow Design ein Logger ein Akteur, eine explizite Abhängigkeit, die hinter einem ganz "normalen" Interface (z.B. eben log4net.ILog) gekapselt wird und in die nutzenden Komponenten injiziert wird. Siehe dazu Ralfs Artikel in der dotnetpro 4/2011. Intern kann die Logging-Komponente durchaus dann wieder ein Flow-Design haben - und zum Üben wäre es sicher lehrreich, so etwas mal zu bauen (Nachbauen von etwas Gutem und Bewährtem ist überhaupt oft eine gute Übung). Für den praktischen Einsatz würde ich aber eher auf log4net zurückgreifen (oder was es eben sonst noch gibt), und es dann auch "wie üblich" nutzen - ich sehe jedenfalls, gerade mit Blick auf das Konzept des Akteurs, kein fundamentales Problem darin, in einer EBC hinzuschreiben
    private static readonly ILog logger = LoggerFactory.GetLogger(typeof(MyEBC));
    ...
    logger.Debug("here we are");
  • Nachtrag, und vielleicht am wichtigsten: bei mir zumindest entsteht der Eindruck, dass Du Dir vor allem über das Design der Pins Gedanken machst. Ich glaube aber nicht, dass es bei EBCs vor allem darum geht. Ein Platinenhersteller wird sich auch nicht als erstes um die Pins an seinen Bauteilen kümmern, sondern darum, welche Bauteile er überhaupt braucht, was die tun sollen und welche Signale sie miteinander austauschen. Analog geht es bei EBCs darum, was die einzelnen Bausteine tun (Ralf spricht oft von den Verben) und welche Daten sie miteinander austauschen bzw. von einem Baustein zum nächsten fließen (deshalb ja auch Flow Design). Wenn Du das sorttiert hast, dann sollten die Pins eigentlich schon fast auf der Hand liegen.
18.05.2011
Matthias Hlawatsch 13,2k 4 9
Es geht mir als erstes darum ein Gefühl für EBC's zu entwickeln insbesondere für die Verdrahtung. Selbst bei einer so simplen Sache wie Logging habe ich schon eine Menge Fragezeichen? Die Implementierung des Loggings selbst ist zweitranging zum einen sind die Anforderungen nicht sehr hoch und selbst wenn würde ich auf bestehendes wie Log4Net zurückgreifen.
bzgl. Verben:
ein Logging Baustein sollte nur eines tun und zwar loggen eines Textes. Insofern würde es nur ein Verb beinhalten z.B. Log(text). Durchreichen ist keine Anforderung eines Log-Bausteines. Insofern kein Output Pin. Korrekt ?
stefc 18.05.2011
Im Prinzip ja ;-)
ILog hat noch Is*Enabled()-Methoden, nützlich z.B. für Performance-Optimierungen. Wenn Du diese Funktion nachbilden willst, bräuchtest Du wohl auch noch einen Out-Pin. Sonst aber nicht.
Ralf hat übrigens in seiner zweiten Antwort das Konzept mit der expliziten Abhängigkeit skizziert, das ich im 3. Punkt erwähnt hatte.
Matthias Hlawatsch 18.05.2011
1
Ich persl. habe mich mit EBC noch wenig beschäftigt.
Wenn ich mir aber so die vorgehensweise Anschaue sollte eine Logging Komponente immer zwischen 2 anderen Komponenten sitzen und die Befehle 1zu1 weitergeben bzw. die Events.
Eine Logging Komponnente darf ja nie ein Endpunkt sein, nach meiner Definition.

Also wäre die einzig denkbare Lösung für mich : Logging Komponnente mit einem 2x In und 2x Out 1x In String und 1x In Action , 1x Out Action und 1x Out zum Kaskadieren.
Dann würde es so laufen: Modul 1 -> Logging + Action LoggingModul -> Action Modul2

Soweit meine unerfahrene Theorie, vll schaut ja gerade Stefan oder Ralf zu und können dazu mehr sagen ?

Grüße
Pawel
17.05.2011
Pawel Warmuth 195 6
Wenn das Logging zwischen geschaltet wird, muss es aber doch die Befehle kennen oder? Ausserdem möchte ich in einer Blackbox Komponente evtl. auch Sachen im Inneren loggen und nicht nur an den In und Out Pin's ??
stefc 17.05.2011
1
Zwischenschalten oder nicht, hängt meines Erachtens davon ab, was du loggen willst. Soll beispielsweise ein Feld in einer Datenklasse gelogged werden, könnte das so aussehen:

Logger<IMessage> logger = new Logger<IMessage>();

logger.Send = m => Console.WriteLine("Ende");
Console.WriteLine("Start");
logger.Process(new Message() { Text = "We are here" });
Console.ReadKey();

class Logger<T> where T : IMessage
{
public Action<T> Send;
public void Process(T t)
{
Console.WriteLine("MessageLogger: " + t.Text);
Send(t);
}
}

class Message : IMessage
{
public string Text { get; set; }
}

interface IMessage
{
string Text { get; set; }
}


Willst Du dagegen innerhalb einer EBC loggen, musst du der wahrscheinlich einen zusätzlichen Pin spendieren:
public Action<string> Log;

diesen hängst du dann an eine EBC, die das aufnimmt, was reinkommt.
18.05.2011
tboerner 509 8
1
Es gibt noch eine Möglichkeit für´s Logging: eine explizite Abhängigkeit.

Normal ist das mit einem Fluss so:

A -> Log -> B

Aber es kann auch so sein:

A (-* Logger) -> B

Dann ist A abhängig von einem Logger. Der wird über das Interface IDependsOn<Logger> in die A-Instanz injiziert:

var logger = new Logger();
var a = new A();
...
a.Result += b.Process;
...
a.Inject(logger);
...

Eleganter finde ich aber immer noch das "Zwischenklemmen" in den Fluss.

-Ralf
18.05.2011
Ralf Westphal 765 1 4
1
Noch eine kleine Variante dazu

Ich habe es bei mir so gelöst dass es ein ILogEnabledEBC , gibt
Dort drin ist der Pin defineirt

Out_Log(LogMessage)

So kann die basis der Boards alle ILogEnabledEBC automatisiert binden.
Das vereinfacht den Verdrahtungsaufwand
19.05.2011
Gentlehag 1,0k 3 8

Stelle deine .net-Frage jetzt!
TOP TECHNOLOGIES CONSULTING GmbH