Ankündigung

Einklappen
Keine Ankündigung bisher.

Aop

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Aop

    Aufgrund dieser Aufforderung http://www.php.de/software-design/78...tml#post591110 würde ich mal gerne das Für und Wider von AOP diskutieren. Ich persönlich halte das für eine gefährliche Sache, aber vielleicht gibt es ja Möglichkeiten und Einsatzzwecke, wo das wirklich notwendig/geeignet ist (Mal unabhängig von PHP). Mit Prozess meine ich nicht Prozesse im programmtechnischen Verständnis, sondern Vorgänge.

    Meine Erfahrung: Die Beispiele, die ich bisher gesehen habe, sorgen in meinen Augen für ein Durcheinander, bei dem nach einiger Zeit keiner mehr durchblickt - Schon gar nicht jemand, der neu in ein Projekt kommt.

    Wo ich das Problem sehe, ist, dass mehr oder weniger willkürlich feste "Applikations-Flows" per - ich nenne es mal so - Hack umgebogen werden können, wodurch feste Strukturen aufgeweicht werden. Auf mich wirkt das so, als ob man einen Prozess ändern möchte, aber aus Faulheit oder sonst welchen Gründen nicht an der Applikation selber Hand anlegen möchte.

    Geeigneter finde ich da Prozessabbildungen über Konfigurationen o. ä., bei denen man festlegen kann, was wo in welchem Prozess geschieht.

    Aber ich lasse mich gerne vom Gegenteil überzeugen


  • #2
    Die Grundvoraussetzung ist zunächst einmal, das Ansinnen zu verstehen, warum AOP erfunden wurde. Von je her stellt sich die Frage nach der Domäne, in die ein Stückchen Code gehört. Sehr typisch, weil leicht zu verstehen, wird bei AOP immer das Protokollieren genommen.

    Annahme: Es gibt eine Klasse "User-Service". Dort gibt es eine Methode "changePassword". Wie verhält es sich nun mit dem Logging, dass diese Methode aufgerufen wurde? Streng genommen gehört die Frage, wie die Klasse "User-Service" an ein Logging-Objekt kommt und dass es loggen muss, nicht zur Businness-Logik des User-Service selbst. Es gehört in eine Domäne Logging. Mit AOP wird genau sowas möglich. Du biegst den Aufruf der Methode in einem für das Logginn zuständigem Aspekt um und führst das Logging dort aus.

    Ein wesentlicher Vorteil ist, dass gleichartiger Code nur einmal geschrieben wird. Hier wieder das Logging: Statt in jeder Methode zu schreiben "Logger:logInfo('enteringMethod '.__CLASS__.'::'.__FUNCTION__);" schreibst du es nur einmal und setzt beispielsweise per Wildcards pauschal alle Methoden einer Klasse. In Flow3 (Steuerung via PHP-Tags) sieht das dann in etwa so aus:
    PHP-Code:
    /**
     * @around MyClass->*
     */
    ..... 
    Das spart Zeit und kann den Code klarer strukturieren. Ein weiterer Punkt ist die Tatsache, dass man aufwändige Listener-Modelle streng genommen nicht mehr braucht oder nicht mehr um beispielsweise referentielle Integritäten sicherzustellen. Hier scheiden sich die Geister.

    Gibt es beispielsweise im User-Service eine Methode deleteUser, brauche ich nur einen Aspekt zu diesem definieren um alle Private Messages des Users zu löschen, sobald der User selbst gelöscht wird. Da die Domäne User von PrivateMessages nichts weiss, ist die einzige Alternative ein aufwändiges Listener/Signal-Modell. Der Nachteil am Signal-Modell ist u.U. der Verwaltungsoverhead. Du musst dich ggf. als Listebner am User-Service registrieren ohne zu wissen, ob überhaupt Code darauf ausgeführt wird. Mittels geschickter Konfigurationsdateien kann man das zwar umgehen, dennoch ist es nicht immer schön.

    Weiteres Anwendungsbeispiel: Gegeben sei ein allgemeines SOA-Modell. Dieses gibt eindeutige fachliche Fehlercodes zurück, wenn im Service was passiert, was nicht OK ist. Auch hier wieder das Logging. Per Aspekt habe ich wenige Codezeilen um an allen SOA-Methoden aufzupassen und per LogError zu potokollieren, falls ein Service auf einen Fehler läuft. Der Code im Service selbst ist sauber.


    Nun kommt das ABER:

    Erst mal ein Zitat von mir selbst.
    Das spart Zeit und kann den Code klarer strukturieren
    Das Wort "kann" ist hier wichtig. Denn AOP kann zur Zeit auch kräftig nach hinten losgehen. Du hast es bereits gesagt, xm22. Das liegt im Wesentlichen an drei Umständen:
    a) Nicht ausreichende Dokumentation und dadurch nicht klare Programmabläufe
    b) Mangelhafte IDE-Unterstützung
    c) AOP zum Selbstzweck ohne Sinn und Verstand.

    zu a) Natürlich verlangt AOP gerade bei komplexeren Abhängigkeiten eine klare Vereinbarung im Projekt. Es werden klare Vorgaben benötigt, für welche Dinge AOP verlangt wird. Und jeder neue Fall sollte zuerst ncohmal durchdacht werden. Damit vermeidet man Willkür. AOP exzessiv häufig einzusetzen, läuft schief. Es gibt zwei Unterscheidungen: Ist der AOP-Ablauf ein optionaler zusätzlicher Ablauf? Das ist beispielsweise bei Logging der Fall, das ist der Fall bei einem Aspekt, der sich um jeden Controller-Aufruf hängt um einen Standard-Admin bei leerer Datenbank vorzubelegen. Ein solcher Aspekt tut zwar was wichtiges, hat aber auf den eigentlichen Controller keinen direkten Einfluss. Zweite Möglichkeit: Ist der AOP-Ablauf ein manipulierener Ablauf? Wenn der AOP-Ablauf dazu dient, tatsächlich die Arbeitsweise zu verändern, Ergebnisse zu verfälschen u.ä., dann muss das nach meiner Erfahrung immer gut dokumentiert werden.

    zu b) Insbesondere in PHP ist AOP neu. IDEs raffen das nicht. Sie unterstützen dich als Entwickler nicht. Aus dem Java-Umfeld, wo man das bereits länger kennt, gibt es einen Vorbild. An jeder Klasse, an jeder Methode, die per Aspekt verändert wird (egal wie) zeigt Eclipse hier einen kleinen Bupperl an. So sieht man, dass es einen besonderen Ablauf gibt. Wenn du so etwas tatsächlich auch für PHP hast (wie gesagt habe ich das mal für Flow3 und Eclipse gebastelt), ist das eine enorme Arbeitserleichterung.
    Stacktraces sind bei Flow3 leicht zu lesen, da die Original-Klassen verwendet werden und es lediglich On-top einen Proxy drauf gibt. Je nach Framework ist das u.U. schwieriger, weil dort Klassen zusammengewoben werden und dann die Original-Dateinamen/Klassennamen nicht mehr verwendet werden.

    c) Natürlich sollte AOP nicht eingesetzt werden, weil mans kann. Man sollte per AOP nicht in der Domäne umherpfuschen. Alles, was zur Domäne A dazu gehört, sollte auch dort entwickelt werden und nicht verstreut in zig Aspekten. Wenn du sowas jedoch in Aspekte verstreust, hast du ein mittelschweres Problem mit der Nachvollziehbarkeit, das ist richtig. Ich setze AOP derzeit auch nur gezielt ein.

    Es gibt bei Flow3 einen kleinen Trick. Aktivieren eines Aspektes via Config. Wieder das Beispiel von oben: Das automatische Anlegen eines Default-Admins. Ich habe eine Konfigurationsoption mit Namen "myapp.create.default.admin". Im Aspekt steht nun in etwa:
    PHP-Code:
    /**
      * @around *->* && ClassWithin(Controller) && Setting(myapp.create.default.admin)
      */ 
    (Genaue Syntax ist anders, müsste ich nachschauen) Was passiert? Dieser Aspekt und damit das Anlegen des Default-Admins wird nur aktiviert wenn die Konfiguration das hergibt. InEntwicklungsumgebung stehts auf true, in Produktiv-Umgebungen später auf false.


    Also: AOP ist sinnvoll, wenn man einige Grundregeln beachtet und es ebend nicht dazu einsetzt, die Arbeitsweise einer Domäne gravierend zu verändern. Ansonsten wirds schnell kontraproduktiv.


    Nachtrag: Zum deleteUser. Wenn ich ein Zusatzplugin habe, was ein Veto einlegt (User darf nicht gelöscht werden, wenn es noch offene Rechnungen gibt), habe ich u.U. ebenfalls ein Problem. In diesem Fall können Aspekte elegant helfen, Bedingungen vor Ablauf des UserService auszuführen und ein veto (= eine Exception) zu werfen.
    www.php-maven.org PHP und Maven vereint: Build/Deploy/Produktion/Konfiguration, Projekt Management, CI, PHPUnit, zahlreiche Frameworks
    Twitter @ https://twitter.com/#!/mepeisen und Facebook @ http://t.co/DZnKSUih

    Kommentar


    • #3
      Ok, das klingt sehr schlüssig. Das zeigt mir aber auch, dass man das wirklich sehr sparsam einsetzen sollte und auch nur an fest vereinbarten Stellen und die Doku das alles ganz genau beschreiben muss. Ein zweischneidiges Schwert. Der Nachteil gegenüber einem Event-System ist für mich allerdings, dass man die Klassen anfassen muss - Zumindest in nächster Zeit, bis sich das mit den Konfigurationen durchgesetzt hat und so etwas standardmäßig benutzt werden kann..

      Kommentar


      • #4
        Welche Klassen musst du denn bei AOP anfassen? Du musst im Prinzip nichts anfassen. Oder meinst du den Engine-Teil, der das zusammenstöpselt? Das sollte hoffentlich unsichtbar vonstatten gehen.
        www.php-maven.org PHP und Maven vereint: Build/Deploy/Produktion/Konfiguration, Projekt Management, CI, PHPUnit, zahlreiche Frameworks
        Twitter @ https://twitter.com/#!/mepeisen und Facebook @ http://t.co/DZnKSUih

        Kommentar


        • #5
          Ein weitres Beispiel:

          Sicherheitschecks. Gegeben sei ein MVC-Modell. Um nun nicht in jede einzelne Action des Controllers Prüfungen einzubauen kann ich einen Aspekt bauen, der sich um jede Action hängt. Dieser Aspekt prüft vor Aufruf: Hat der eingeloggte User die Rechte? Wenn Nein, springt es zu einem Alternativablauf (z.B. Redirect an eine Access-Denied-Seite).

          Ebenfalls im MVC-Modell die Verarbeitung von Plugins, die auf beliebiger Seite ausgeführt werden. Beispielsweise das Verändern der Sprache oder der Login/Logout. Diese lassen sich ebenfalls per Aspekt um die Actions eines Controllers drumherum bauen.

          Bei solchen Dingen ist der Programmablauf nach wie vor sehr klar. Der Code wird nicht aufgebläht durch Aufruf und Delegation von irgendwelchen Aufgaben. In einer Doku steht dann idealerweise: Login/Logout wird in Aspekt XYZ umgesetzt.

          Ich habe beispielsweise einen Aspekt, der auf ein Tag hört. Dieser Aspekt ist ebenfalls eine Berechtigungsprüfung, ob eine Methode aufgerufen werden soll und bewirkt zudem, dass ich dieses Recht im Admin-Bereich vergeben kann.
          Das sieht dann so aus:
          PHP-Code:
          // Ziel-Methode
          /**
           * @acl_method "Meine Super Methode"
           */
          public function foo() {}


          // Aspekt
          /**
           * @before MethodTaggedWith(acl_method)
           */ 
          Gerade solche Aspekte, die sich ausgehend von einem Tag erst an die Methode/Klasse hängen sind im Prinzip, auch wenn sie die Verarbeitung ändern, dennoch in orgendeiner Art und Weise sichtbar und damit halbwegs nachvollziehbar. Solange jeder weiss, was das Tag bedeutet. Womit wir auch wieder bei der Doku sind.
          www.php-maven.org PHP und Maven vereint: Build/Deploy/Produktion/Konfiguration, Projekt Management, CI, PHPUnit, zahlreiche Frameworks
          Twitter @ https://twitter.com/#!/mepeisen und Facebook @ http://t.co/DZnKSUih

          Kommentar


          • #6
            Da lohnt sich wahrscheinlich schon - Ich habe selber für mein Framework nach einer entsprechenden ACL-Funktionalität gesucht und bin jetzt bei Callbacks hängen geblieben - Alles nicht so schön..

            Was ich an Bsp. gesehen habe, war, dass Prozesse damit umgebogen wurden. Da jedoch halte ich das in vielen Fällen für kontraproduktiv.

            Kommentar


            • #7
              Das Umbiegen von Abläufen ist interessant wenn du Module/Plugins kundenspezifisch anpassen möchtest.

              Da PHP das überladen von Methoden wie man es z.B. aus Delphi kennt nicht unterstützt müsstest du für kundenspezifische Anpassungen das Modul entsprechend abändern. Das Problem was sich hierbei ergibt: bei vielen Kunden und vielen individuellen Anpassungen hast du dann zig Projekte wo allesamt unterschiedliche Module laufen, und willst du einen globalen Fehler durch ein zentrales Update beheben wird das nichts mehr weil alle Module individuellen Code beinhalten.

              Das muss die Doku aber hergeben bzw. sollte es ein leichtes sein, wieder mit Hilfe von Aspekten, den Ablauf zu verfolgen und die Bedingung für die Prozessumleitung nachzuvollziehen.

              Ich frage mich aber wie man es realisiert das der Aspekt aufgerufen wird. Läuft das über __call? Des weiteren Frage ich mich wie es mit dem Zugriff auf private/protected Eigenschaften und Methoden von Klassen aussieht. Wie realisiert man es das ein Aspekt hierauf zugreifen kann, falls nötig, diese aber von außerhalb der Klasse weiterhin nicht zugänglich sind?
              "Alles im Universum funktioniert, wenn du nur weißt wie du es anwenden musst".

              Kommentar


              • #8
                Ich spreche mal von Flow3, wo das relativ umfassend umgesetzt ist. Drei Grundvoraussetzungen/ Vereinbarungen:
                a) Auf Include-Techniken wird umfassend verzichtet. Es kommen entsprechend versierte ClassLoader zum Einsatz.
                b) Für diverse Techniken (beispielsweise Serialisierung) kommen versierte Lösungen zum Einsatz. Vieles geschieht unsichtbar für den Entwickler, beispielsweise wird eine Klasse als Session-relevant markiert und damit weiss der Objekt-Container, wo sie herzukommen hat.
                c) Es gibt einen Objektcontainer und eine Objektfactory, auf "new" wird verzichtet.

                In Flow3 wird jede Klasse, die von Aspekten betroffen ist, über eine Proxy-Klasse realisiert. Dieser Proxy tut nichts anderes als die eigentliche Klasse zu überschreiben, um selbst die Aspekte aufzurufen. Es werden gezielt die Ziel-Methoden überschrieben. Das ist eine der Ecken, was Flow3 derzeit (zur Entwicklungszeit) sehr langsam macht. Es scannt permanent als Teil des Bootstrap alle Dateien auf Änderungen und ermittelt dann die Auswirkungen auf Klassen, Proxies und Aspekte. Natürlich lässt sich das für produktive Umgebungen ausschalten. Das Vererben hat einen wesentlichen Vorteil: Stack-Traces zeigen auf die ursprüngliche Klasse. Sowohl bei Aspekten, als auch bei den Ziel-Klassen.

                Flow3 kann, da es eine reine PHP-Lösung ist, neimals bestmögliche Sicherheit bieten. Es gibt in den Proxies immer einen Getter/Setter und eine Call-Methode, du kannst also theoretisch von außen, wenn du weisst dass es ein Proxy ist, herumpfuschen. Generell kann ein Aspekt vom Design her auch Setter und Getter bedienen, sowie andere Methoden eines Ziel-Objektes aufrufen (auch geschützte). Das kann zu Sicherheitsproblemen führen. Ein korrumpiertes Plugin könnte beispielsweise dafür sorgen, dass es das Passwort eines User-Objektes per Aspekt verändert.

                Ich denke aber, dass man über mögliche Sicherheitslöcher aus zwei Gründen nicht diskutieren sollte: a) wenn einer bereits soweit ist, gezielt Code einzuschleusen, findet er genug Wege, auch ohne Aspekte das System zu übernehmen. b) Der Sicherheitsgedanke kann in reinen PHP-Lösungen nie hoch genug sein, dazu gibt es, Code einmal eingeschleust, zu viele Varianten, anzugreifen.
                Denkbar sind aus Sicherheitssicht Varianten, bei denne Flow3 den direkten Aufruf der Proxy-Methoden außerhalb berechtigter Aspekte verbietet. Auch denkbar ist eine echte C-Extension, die die Proxy-Methoden nicht als öffentliche Methoden anbietet und die Sicherheit dadurch deutlich erhöht.
                www.php-maven.org PHP und Maven vereint: Build/Deploy/Produktion/Konfiguration, Projekt Management, CI, PHPUnit, zahlreiche Frameworks
                Twitter @ https://twitter.com/#!/mepeisen und Facebook @ http://t.co/DZnKSUih

                Kommentar


                • #9
                  Das klingt sehr anch einem System nach dem ich lange gesucht habe. Denn in meinem CMS mache ich es mit Modulen ähnlich.

                  Ein Blick in Flow3 dürfte nicht schaden. Nur leider darf ich meinen Systemkern dann wohl mal wieder neu schreiben (>_<°) weil ich schon jetzt viele neue Ideen habe um bestehende Abhängigkeiten aufzulösen.
                  "Alles im Universum funktioniert, wenn du nur weißt wie du es anwenden musst".

                  Kommentar


                  • #10
                    Wenn dein CMS ein Privates ist, helfe ich dir da gerne bei Oder halt auf die neue Typo3-Version warten. Dann hat man ein CMS, wo man nur gezielt erweitern/anpassen muss.
                    www.php-maven.org PHP und Maven vereint: Build/Deploy/Produktion/Konfiguration, Projekt Management, CI, PHPUnit, zahlreiche Frameworks
                    Twitter @ https://twitter.com/#!/mepeisen und Facebook @ http://t.co/DZnKSUih

                    Kommentar

                    Lädt...
                    X