AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?
Thema durchsuchen
Ansicht
Themen-Optionen

Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?

Ein Thema von BrightAngel · begonnen am 7. Feb 2017 · letzter Beitrag vom 8. Feb 2017
Antwort Antwort
Seite 1 von 2  1 2      
BrightAngel

Registriert seit: 13. Mär 2007
130 Beiträge
 
#1

Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?

  Alt 7. Feb 2017, 20:01
Guten Abend zusammen!

Es gibt ein Thema mit dem ich mich in den Jahren immer wieder intensiv auseinandersetzen musste und mit dem jeder von uns mehrfach täglich Kontakt hat und das wir glaube ich sehr intuitiv benutzen: Den Kontrollfluss von Ereignissen.

Stellt euch ein einfädiges Programm vor. Ereignisse (z.B. onClick) sind zentraler Bestandteil der Programmarchitektur. Insbesondere wird in der gewählten Architektur ein Ereignissystem eingesetzt, das bei einem einzelnen Ereignis mehrere Listener informieren kann (also zum Beispiel ein einzelnes "onClick" dazu, dass mehrere Programmroutinen nacheinander ausgeführt werden).

[Edit]
Nachdem "Der schöne Günther" mir bereits Feedback gegeben hat: Seine Zusammenfassung trifft mein Anliegen sehr gut; wer lieber meine Frage kurz und knapp lesen möchte, den verweise ich gerne einen Post weiter. Wenns um Details geht, bitte hier weiterlesen.
[/Edit]

Jetzt die Frage: Wie soll der Kontrollfluss eurer Meinung nach laufen? Also vorweggenommen: Beide hier vorgestellten Kontrollflussszenarien habe ich so in etwa schon gesehen und haben jeweils ihre Vor- und Nachteile. Ich glaube, dass man mit beiden Kontrollflussmechanismen in der Lage ist, die selben Programme zu schreiben. Es ist nur eine Frage der "Schönheit"

Hier jetzt mal ein Beispielablauf (nur ganz grob):
  1. Das Ereignis tritt ein (z.B. Maus Ereignis "click" wird vom Betriebssystem an das Programm weitergereicht)
  2. Ereignisverteilungsroutine wird betreten
  3. Ein Listener, der zuvor auf dem Ereignis angemeldet wurde wird betreten
  4. Dieser Listener löst ein anderes Ereignis aus (z.B. ein synthetisches "change"-Ereignis)

Ab hier unterscheiden sich jetzt die beiden Ereignisarchitekturen.
Kontrollflussbeschreibung "MachsSpäter" (defer):
  1. Das Ereignissystem merkt sich das "change"-Ereignis für die spätere Behandlung
  2. Es betritt weitere Listener aus dem "click" Ereignis
  3. Der Kontrollfluss kehrt aus der "click" Ereignisverteilungsroutine zurück und findet das zuvor gemerkte "change"-Ereignis
  4. Das "change"-Ereignis wird analog zum gerade beschriebenen Prozess abgearbeitet (und kann auch weitere synthetische Ereignisse auslösen, die dann wiederrum bis nach dem "change"-Ereignis aufgehoben werden)
  5. Ein Äquilibrium wird erreicht; es sind keine weiteren Ereignisse abzuarbeiten.

Kontrollflussbeschreibung "MachsSofort" (immediate):[*]Das Ereignissystem betritt die Ereignisverteilungsroutine des "change"-Ereignisses[*]Die Listener des "change"-Ereignisses werden der Reihe nach abgearbeitet (und dabei können weitere synthetische Ereignisse ausgelöst werden, die dann wiederrum direkt abgearbeitet werden)[*]Der letzte Listener des "change"-Ereignisses wurde abgearbeitet.[*]Die verbliebenen Listener des "click"-Ereignisses werden abgearbeitet. Ereignisbehandlung analog.[*]Der letzte Listener des "click"-Ereignissses wurde abgearbeitet; es ist nichts mehr zu tun.[/LIST]
Ab hier treffen sich beide Möglichkeiten wieder:
  1. Es wird wieder auf weitere Betriebsystemnachrichten gewartet (typischerweise irgendwo im run-loop)

Folgende Eigenschaften sind zu beobachten:
  • Bei "defer" werden die Ereignisse streng nacheinander abgearbeitet, bei "immediate" kann es passieren, dass ein Listener von "click" NACH einem Listener von "change" abgearbeitet wird
  • "defer" hält künslich eine Ereignisliste vermutlich irgendwo im Heap, während bei "immediate" diese Information implizit durch die Listenerlisten und die Iterationsvariablen auf dem Stack gespeichert hält

Dadurch ergeben sich bei beiden Strukturen verschiedene Vor- und Nachteile durch die Reihenfolge der Abarbeitung. Zum Beispiel gibt es auch parametrisierte Ereignisse, deren Parameter vielleicht irgendwo den Zustand im Programm ändern. Klar, man kann sich als Programmierer auf beides einstellen; aber was gefällt euch mehr? Was findet ihr intuitiver? Seht ihr absolute Totschlagargumente, die absolut gegen die eine Architektur sprechen und für die andere? Habt ihr eine dritte Lösung, die komplett anders aussieht, aber ähnliche Architektur Anforderungen (mehrfache Listener an einem Ereignis, Single Threaded, usw) erfüllen?

Gruß, Brighty

P.S. Ich habe gerade gesehen, dass die Listenabschnitte immer mit "1." anfangen. Der Forensoftware ist mein LIST=5 (bzw. LIST=10) scheinbar nicht Hinweis genug, dass die Liste da mit "5." (bzw. "10.") beginnen soll. Ihr müsst euch die Zahlen entsprechend vorstellen.
Do you have the email of god??? --- I have to tell him that I'm happy to be born!

Geändert von BrightAngel ( 7. Feb 2017 um 22:18 Uhr)
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.159 Beiträge
 
Delphi 10 Seattle Enterprise
 
#2

AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?

  Alt 7. Feb 2017, 22:03
Vielleicht liegt es an der Uhrzeit, aber ich musste mehr als einmal lesen um es zu verstehen. Eine kleine Skizze vom Ablauf*hätte (mir zumindest) geholfen

In einem Satz zusammengefasst: An einem OnClick-Event hängen mehrere Handler. Einer dieser Handler ändert z.B. eine Eigenschaft was wiederum ein OnChange-Event auslöst. Sollte man nun
  • Die Handler des OnChange-Events abarbeiten um danach die restlichen Handler von OnClick abzuarbeiten
  • Oder die Handler von OnChange erst nach dem vollständigen Abarbeiten aller Handler des "laufenden Events" (also OnClick) abarbeiten

Richtig verstanden?

Vielleicht habe ich einfach noch nicht genug von der Welt gesehen, aber den "defer"-Ansatz habe ich weder irgendwo einmal gesehen, noch finde ich das in irgendeiner Weise intuitiv. Bei einem "Mach sofort"-Ansatz*könnte ich Events*deaktivieren, etwas tun und danach wieder aktivieren. Mit dem "defer"-Ansatz verliere ich das doch, oder?

Ganz zu schweigen von dem Mehraufwand. Was z.B. wenn ich einen Handler entferne, der aber noch in irgendeiner "Mache später"-Queue steckt? Schwierig. Mir fehlt ein konkretes Beispiel wo der "defer"-Ansatz irgendeinen Vorteil hat. Was hierdurch einfacher wird.*

Außerdem sehe ich nicht was an einem Event so "besonders" ist dass man es aufstauen sollte. Warum wird ein Handler der ein internes Feld ändert sofort ausgeführt, ein anderer der z.B. auf eine Property geht (deren Setter ein Event auslöst) aber später? Bzw. der Setter würde ausgeführt, nur der Code hinter dem Event nicht? Jeder*Code der hinter dem bewussten Ausführen eines Events steht müsste fortan davon ausgehen müssen, dass die*Folgen noch nicht eingetreten sind.

Ziemlich verwirrend. Vielleicht aber auch nur für mich.

PS: Mich haben deine "Beginnt mit"-Dinger verwirrt, vor allem da du erst ganz unten erklärst was du damit meintest. Lass die*Auflistung doch wie sie ist, das versteht denke ich trotzdem jeder.
  Mit Zitat antworten Zitat
BrightAngel

Registriert seit: 13. Mär 2007
130 Beiträge
 
#3

AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?

  Alt 7. Feb 2017, 23:00
Vielleicht liegt es an der Uhrzeit, aber ich musste mehr als einmal lesen um es zu verstehen. Eine kleine Skizze vom Ablauf*hätte (mir zumindest) geholfen
Kann sein, dass es die Uhrzeit ist, aber ich habe auch ein bisschen gebraucht, um das auch nur zu formulieren... Ich wollte möglichst viel Detail schaffen, damit man die ganzen Ecken und Kanten unterwegs mitbekommt. Hab mich da wohl verzettelt. Vielen dank, dass du dich trotzdem damit befasst hast!

In einem Satz zusammengefasst: An einem OnClick-Event hängen mehrere Handler. Einer dieser Handler ändert z.B. eine Eigenschaft was wiederum ein OnChange-Event auslöst. Sollte man nun
  • Die Handler des OnChange-Events abarbeiten um danach die restlichen Handler von OnClick abzuarbeiten
  • Oder die Handler von OnChange erst nach dem vollständigen Abarbeiten aller Handler des "laufenden Events" (also OnClick) abarbeiten

Richtig verstanden?
Genau! Ich habe mir erlaubt, meinen ursprünglichen Post auf deinen verweisen zu lassen. Hilft vielleicht auch anderen Lesern

Vielleicht habe ich einfach noch nicht genug von der Welt gesehen, aber den "defer"-Ansatz habe ich weder irgendwo einmal gesehen, noch finde ich das in irgendeiner Weise intuitiv.
Ja, das "defer" sieht man normalerweise nicht. Es gibt ein paar Beispiele, die aber eher vereinzelt auftauchen: In Java gibt es mit der runLater-Methode die Möglichkeit die Ausführung auf dem UI-Thread zu verzögern.
In Javascript sieht man manchmal Codefragmente
Code:
setTimeout(function() { ... }, 0);
, die auch diesen Zweck des Verzögerns erfüllen. Aber genau diese Behelfsstellen haben mich dazu angeregt näher darüber nachzudenken und meinen Code mancherorts zu überdenken.
Das gruslige zur Intuition: Je länger ich mich damit beschäftige, desto interessanter finde ich eben auch diesen anderen Kontrollfluss.

Bei einem "Mach sofort"-Ansatz*könnte ich Events*deaktivieren, etwas tun und danach wieder aktivieren. Mit dem "defer"-Ansatz verliere ich das doch, oder?
Genau, das ist zum Beispiel ein Vorteil davon. Das Deaktivieren ist aber nicht so häufig und bei vielen EventListenern pro EventSource kann es vorkommen, dass das Entfernen und Hinzufügen vielleicht teurer wird. Zudem impliziert so eine Codestelle meistens, dass man zirkuläre Abhängigkeiten vermeiden möchte. Vielleicht findet man da manchmal mit ein bisschen Nachdenken schönere "Abbruchkriterien" als das temporäre deregistrieren des Listerners? Aber ganz von der Hand weisen kann man dein Argument eben auch nicht...

Ganz zu schweigen von dem Mehraufwand. Was z.B. wenn ich einen Handler entferne, der aber noch in irgendeiner "Mache später"-Queue steckt? Schwierig. Mir fehlt ein konkretes Beispiel wo der "defer"-Ansatz irgendeinen Vorteil hat. Was hierdurch einfacher wird.*
Thema Mehraufwand: Theoretisch ist eine zentrale Liste mit Ereignissen quasi genau das selbe wie beim Runloop von Betriebssystemereignissen. Auch die werden gecached, wenn der Faden noch nicht soweit ist. Eine LinkedList zusätzlich oder so reicht da vmtl.
Thema Handler entfernen: Ja, wenn man Handler entfernt und hinzufügt während der Eventbehandlung ist so ein Sonderfall den man bei beiden Implementierungen genau betrachten muss: Man will im Optimalfall das gerade laufende Ereignis allen Listenern zustellen, die zum Triggerzeitpunkt des Ereignisses registriert waren.
"defer" im Speziellen bildet sowas wie einen "ripple"-Effekt. Ein (zugegeben sehr synthetisches) Beispiel: zwei Listener auf ein und dem selben Event ändern je eine Eigenschaft von einem Rechteck.
ListenerWidth ändert die Breite des Rechtecks und triggert ein weiteres Event zur Berechnung des Flächeninhalts. ListenerHeight ändert die Höhe des Rechtecks und triggert auch das Flächeninhaltsereignis. Bei "defer" ändern sich die Dimensionen des Rechtecks zuerst und dann wird zwei Mal der selbe Flächeninhalt berechnet (wobei wenn die Flächeninhaltsberechnung weitere Ereignisse auslöst, sie das durch ein identisches, bei der ersten Berechnung gecachtes Ergebnis beim zweiten Mal gar nicht auslösen muss!), bei "immediate" werden die Ereignisse in anderer semantischer Reihenfolge aufgelöst (es wird dazwischen einmal ein Flächeninhalt berechnet, der vermutlich nicht wichtig ist).
Bei "defer" könnte man so zum Beispiel die Dimensionen ändern; ohne, dass der Flächeninhalt sich zwischendurch kurz "flackernd" auf einen Zwischenwert ändert (Beispiel: 3x6 wird zu 2x9 und der Flächeninhalt bleibt 18)

Außerdem sehe ich nicht was an einem Event so "besonders" ist dass man es aufstauen sollte. Warum wird ein Handler der ein internes Feld ändert sofort ausgeführt, ein anderer der z.B. auf eine Property geht (deren Setter ein Event auslöst) aber später? Bzw. der Setter würde ausgeführt, nur der Code hinter dem Event nicht? Jeder*Code der hinter dem bewussten Ausführen eines Events steht müsste fortan davon ausgehen müssen, dass die*Folgen noch nicht eingetreten sind.
Genau, aber wer sagt, dass Listener in der gleichen Reihenfolge aufgerufen werden? Wenn du beispielsweise zwei Listener hast und der erste sich kurz deregistriert und dann wieder registriert (und dann vielleicht damit an zweiter Stelle der Ausführung landet) und danach ein gleiches Ereignis ausgelöst wird, dann ändert sich die Ausführungsreihenfolge der Listener zwischen zwei Ereignissen...

Ziemlich verwirrend. Vielleicht aber auch nur für mich.
Nein, du hast es erfasst! Es IST ziemlich verwirrend. Wenn man da eine Weile drüber nachdenkt, wird es irgendwie komisch... Vielleicht wirklich die Uhrzeit.

PS: Mich haben deine "Beginnt mit"-Dinger verwirrt, vor allem da du erst ganz unten erklärst was du damit meintest. Lass die*Auflistung doch wie sie ist, das versteht denke ich trotzdem jeder.
Danke fürs Feedback; habe es angepasst!
Do you have the email of god??? --- I have to tell him that I'm happy to be born!

Geändert von BrightAngel ( 7. Feb 2017 um 23:17 Uhr)
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.276 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?

  Alt 8. Feb 2017, 10:13
Hallo,
also, welcher der Ansätze implementiert wird, entscheidet doch der Programmierer, oder nicht?

Beide Ansätze haben Nachteile.

Vorteil des "Mache es sofort" ist ja der, dass das die VCL direkt "unterstützt",
wenn man nicht gerade mit Threads arbeitet.

Bsp:
Listener 1 hängt am Edit1.OnChange
Listener 2 hängt am Edit2.OnChange
Listener 3 hängt am Edit3.OnChange

Edit1.Text :=
'bla' -> Edit1.OnChange -> Listener 1 wird informiert ->
Listener1 setzt Edit2.Text -> Edit2.OnChange -> Listener 2 wird informiert

jetzt geht es mit Edit1.OnChange und Listener 3 weiter

Probleme könnte es geben, wenn z.B. Listener 3 auch wieder was an Edit1 macht
Heiko
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.159 Beiträge
 
Delphi 10 Seattle Enterprise
 
#5

AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?

  Alt 8. Feb 2017, 10:47
Es gibt ein paar Beispiele, die aber eher vereinzelt auftauchen: In Java gibt es [...] . In Javascript sieht man manchmal Codefragmente [...]
Klar, an "Mache das später" setzt ja auch niemand etwas aus. Das ist völlig legitim, gibt es überall, auch hier in Delphi immer wieder gerne. Aber das ist doch ganz allgemein. Das hat nichts speziell mit Events und ihren Handlern zu tun. Außerdem sagt da der Entwickler explizit "Mache das, aber nicht unbedingt sofort". Man sieht es direkt.


Das "Sparen" von unnötigen Berechnungen am Beispiel deines Rechtecks kann ich auch nicht ganz nachvollziehen: Erstens fällt der Ansatz hier schon auf die Nase wenn der ListenerHeight beispielsweise nicht einfach stumpf +10 auf die Höhe gibt, sondern die Höhe nur ändert wenn z.B. der Flächeninhalt z.B. kleiner ist als X. Er bekommt jetzt einen falschen Flächeninhalt.

Das "Sparen" von unnötigen Berechnungen in dem Beispiel ließe sich einfacher und offensichtlicher lösen indem beim Ändern von Width und Height der berechnete Flächeninhalt entfernt wird ("invalidiert") und erst wieder ("lazy") berechnet wird wenn die Flächeninhalt-Property abgefragt wird. Nur so als Beispiel.



Ich bleibe dabei: Gegen "Mach später" allgemein kann man nichts einwenden. Aber speziell an Events diese Philosophie "aufzuzwingen" wäre krass gegen meine Erwartungshaltung.
  Mit Zitat antworten Zitat
BrightAngel

Registriert seit: 13. Mär 2007
130 Beiträge
 
#6

AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?

  Alt 8. Feb 2017, 12:22
Ich bleibe dabei: Gegen "Mach später" allgemein kann man nichts einwenden. Aber speziell an Events diese Philosophie "aufzuzwingen" wäre krass gegen meine Erwartungshaltung.
Okay. Vielen Dank für dein Feedback! Da das ganze Thema ja schon ein bisschen beackert wurde: Was meinen die anderen? Mir würde ab jetzt eine kurze Richtungstendenz von möglichst vielen Leuten interessieren.

Brighty
Do you have the email of god??? --- I have to tell him that I'm happy to be born!
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.343 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?

  Alt 8. Feb 2017, 12:43
Ich verstehe Dein Anliegen nicht so richtig.

Im Regelfall sollte ein Ereignis m.E. unmittelbar behandelt werden.
Die Reihenfolge und Anzahl resultierender Behandlungen kann ggf. variieren und sollte i.d.R. keine schädlichen Auswirkungen haben.

Wenn es doch mal zu irgendwelchen Seiteneffekten kommt muss man diese entsprechend explizit berücksichtigen (durch Einsatz von Flags o.ä.).

Sofern man die Geschäftslogik und die GUI ordentlich voneinander trennt, hat man solche Probleme womöglich gar nicht. Bei der Delphi-Architektur verlangt das natürlich schon eine gewisse Selbstdisziplin.


Vielleicht bin ich aber auch auf dem völlig falschen Gleis und habe die Fragestellung überhaupt nicht verstanden...
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
BrightAngel

Registriert seit: 13. Mär 2007
130 Beiträge
 
#8

AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?

  Alt 8. Feb 2017, 13:47
Im Regelfall sollte ein Ereignis m.E. unmittelbar behandelt werden.
Genau um dieses "unmittelbar" geht es: Dadurch, dass mehrere Listener informiert werden entsteht das Problem, dass das nicht "zeitgleich" passieren kann.

Die Reihenfolge und Anzahl resultierender Behandlungen kann ggf. variieren und sollte i.d.R. keine schädlichen Auswirkungen haben.
Genau. Das ist quasi das Ziel. Das stimmt halt nur, wenn zwischen den Ereignissen keine Abhängigkeit besteht. Teilweise gibt es die aber schon; bzw sind.

Sofern man die Geschäftslogik und die GUI ordentlich voneinander trennt, hat man solche Probleme womöglich gar nicht. Bei der Delphi-Architektur verlangt das natürlich schon eine gewisse Selbstdisziplin.
Klar, man plant da definitiv vorher. Dafür Entwirft man ja seine Software vorher Trotzdem geht das nicht immer perfekt und/oder mancherorts nur künstlich zum Beispiel durch das Einführen zusätzlicher Indirektion. Das kann auch nur in der GUI passieren, wenn mehrere Stellen der UI korrelieren und bei Änderungen miteinander reagieren.

Ich gebe zu, dass das alles ein wenig künstlich wirkt, aber ich bin auf der Suche nach einem möglichst schönen Paradigma was Ereignisse angehen.

Brighty
Do you have the email of god??? --- I have to tell him that I'm happy to be born!
  Mit Zitat antworten Zitat
Benutzerbild von ConnorMcLeod
ConnorMcLeod

Registriert seit: 13. Okt 2010
Ort: Bayern
490 Beiträge
 
Delphi 10.4 Sydney
 
#9

AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?

  Alt 8. Feb 2017, 14:01
Das erinnert mich an SendMessage und PostMessage. Was wäre bei diesen die bessere Variante. Antwort: je nach Anwendungsfall
Nr.1 Delphi-Tool: [F7]
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.343 Beiträge
 
Delphi 11 Alexandria
 
#10

AW: Kontrollflussarchitektur bei Ereignissen: Geschmackssache?!?

  Alt 8. Feb 2017, 14:06
Zu dem Schluss komme ich auch.

Als Paradigma würde ich vielleicht formulieren: Abhängigkeiten zwischen Modulen und Ereignissen nach Möglichkeit vermeiden. Wo das nicht möglich ist, Einzelfall-Lösungen finden, die mit den Abhängigkeiten umgehen können (und die können ganz unterschiedlich ausfallen).
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:44 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz