Ankündigung

Einklappen
Keine Ankündigung bisher.

Projekt-Konzept & Struktur

Einklappen

Neue Werbung 2019

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

  • Projekt-Konzept & Struktur

    Hallo,

    ich "sitze" im Moment scheinbar wirklich auf dem Schlauch - hoffe aber mich mit meiner Frage jetzt nicht völlig zu blamieren. Da das ein etwas längerer Post wird bedanke ich mich schonmal zu Anfang für die Ausdauer das alles zu lesen

    -----

    Im habe ein "Konzept" für eine Webanwendung welche ich in PHP programmieren möchte. Die technischen Rahmenbedingungen sind folgende:
    - Composer wird genutzt
    - Silex wird als PHP-Framework eingesetzt
    - Es wird mit Twig gearbeitet

    Folgende Informationen zum Projekt selbst:
    - Es besteht aus zwei Bereichen "Admin" und "Frontend"
    - Später kommt ggf. noch ein Bereich "User" dazu
    - Das System soll / wird Modular

    Nur um verwirrung zu vermeiden: Als Bereich definiere ich teile einer Seite die zwar zur Seite gehören, aber auch eigene Resourcen wie Konfigurationsdateien, Übersetzungen, Templates, etc. haben.

    -----

    Ich finde keine "sinnvolle" Ordnerstruktur für mein Projekt. Wie oben bereits beschrieben, soll Composer (inkl. des Autoloading-Systems) benutzt werden.

    Folgende Idee hatte ich (leht um ehrlich zu sein etwas an Symfony an):
    Code:
    /
    - application
     - Admin
       ... Bereich spezifische Unterordner ...
     - configs
     - Frontend
       ... Bereich spezifische Unterordner ...
     - translations
     - templates
    - src
    - vendor
    - web
    Warum gefällt mir das nicht?
    Ich finde den Mix aus Groß- und Kleinschreibung bei den Ordnernamen irgendwie Bad-Style, außerdem bin ich mir nicht sicher ob das vom Software-Design her nicht irgendwie "besser" geht. Bei Umsetzung wie hier beschrieben, müsste ich für "src" und "application" jeweils eine Ausnahme im Autoloading in der "composer.json" definieren.

    Ich hatte mir auch schon überlegt, "admin" und "frontend" kleinzuschreiben aber dann müsste ich für jeden Bereich eine Ausnahme in der "composer.json" setzten was mir missfällt.

    Wenn ich mich schonmal traue euch was zu fragen Kenn jemand ggf. gute Literatur die sich mit sowas und anderen Themen rund um Software-Design beschäftigt?

    -----

    Nachtrag

    Nach dem Absenden ist mir doch noch was eingefallen, das fehlt!

    - Alle aufrufe der Seite und der einzelnen Bereiche laufen über die index.php im "web"-Ordner
    - Die Ordner "config", "translation" sowie "templates" beinhalten Anwendungsweit genutzte Daten wie z.B. die Konfiguration für die Datenbank usw.
    - Ziel dieser "Architektur" ist es dublicated Code / Config soweit wie möglich zu vermeiden, aber trotzdem die Möglichkeit zu haben "im Worst-Case" einzelne Bereich alleinstehend zu betreiben!
    Gruß,
    SebTM


  • #2
    Mach doch in applications noch einen Ordner area und da drin dann die großgeschriebenen Bereiche

    Kommentar


    • #3
      Hallöchen,

      verschwende nicht zu viel Energie am Design der Ordnerstruktur. Schau dir am besten ein paar Projekte auf GitHub an und lerne von den Erfahrungen anderer. Ich persönlich gliedere meine Projekte grob nach Features und Komponenten. Frontend und Backend sind bei mir meistens zwei separate (AngularJS-)Anwendungen. Gemeinsam genutzte Komponenten werden ausgelagert und isoliert behandelt. PHP nutze ich ausschließlich um eine zentrale API zu bauen, welche alle notwendigen Methoden für die Anwendungen bereitstellt.

      Viele Grüße,
      lotti

      Kommentar


      • #4
        Hallo,

        danke für eure Hilfe - die Idee mit dem Unterordner ist gut. Ich würde mich freuen, wenn Ihr mir noch mehr Tipps bzgl. der Architektur zu diesem spezifischen Projekt geben könntent. Falls ich irgendwelche Standards (die ich wohl noch nicht kenne) oder ähnliches falsch mache bin ich über jeden Hinweis dankbar!

        Nachtrag
        Werde mir auf Github ein paar OpenSource-Projekte ansehen, ggf. lagere ich meine Libaries auch aus um Sie via Composer zu laden.
        Gruß,
        SebTM

        Kommentar


        • #5
          Hallöchen,

          Zitat von SebTM Beitrag anzeigen
          danke für eure Hilfe - die Idee mit dem Unterordner ist gut. Ich würde mich freuen, wenn Ihr mir noch mehr Tipps bzgl. der Architektur zu diesem spezifischen Projekt geben könntent. Falls ich irgendwelche Standards (die ich wohl noch nicht kenne) oder ähnliches falsch mache bin ich über jeden Hinweis dankbar!
          Na ja, eine Verzeichnisstruktur macht noch keine Softwarearchitektur. Wie bereits angedeutet ist es sinnvoll, seine Anwendung, sofern eine hohe Komplexität absehbar ist, in Features und Komponenten zu gliedern. Was ich ungern mache und oft sehe ist eine Gruppierung nach Typ: Controller, View, Model, .. das hat den entscheidenden Nachteil, dass zusammengehörige Dateien im gesamten Projekt verstreut sind.

          Die Verzeichnisstruktur einer simplen PHP-Anwendung sieht bei mir meistens in etwa so aus:
          Code:
          + api/
            + app/
              cli.php
              ..
            + bin/
            + config/
              db.php
              di.php
              routes.php
            + migrations/
              Migration.php
            + orm/
              User.orm.xml
              ..
            + src/
              + core/
              + users/
              ..
            + tests
              + core/
                CoreTest.php
              + users/
                UserTest.php
            + vendor/
            + web/
              .htaccess
              index.php
              ..
            composer.json
          Den PSR-4 Autoloader setze ich dabei manuell auf die Unterverzeichnisse von src/ an. Bei wirklich kleinen Projekten lasse ich diese zusätzliche Modularisierung ganz weg. Es würde im Prinzip auch nichts dagegen sprechen, dort einfach neue Namensräume aufzumachen.

          Zitat von SebTM Beitrag anzeigen
          Nachtrag
          Werde mir auf Github ein paar OpenSource-Projekte ansehen, ggf. lagere ich meine Libaries auch aus um Sie via Composer zu laden.
          Langfristig erleichtert es die Wartung ungemein, wenn man klare isolierte Komponenten mit spezifischen Aufgaben hat. Auch lassen sich ausgelagerte Komponenten ohne Umwege in anderen Projekten wiederverwenden.

          Viele Grüße,
          lotti

          Kommentar


          • #6
            Hallo,

            Vielen Dank schonmal an @lottikarotti für die ausführliche Antwort und das Beispiel. Ich ging davon aus das die Projektstruktur bzw. Verzeichnisstruktur zum größten Teil in die Kategorie "Softwarearchitektur" gehört - daher hatte ich das so geschrieben.

            Dein Beispiel sieht für mich sehr interessant aus - ich habe mir hier schon einige Überlegungen gemacht, wie ich die Vorteile für mein Projekt adaptieren kann. Wo ich noch nicht ganz durchsteige, was meinst du mit Unterteilung in "Komponenten" bzw. "Features"?

            Villeicht ist hier mein Projekt bzw. dessen Aufbau das eigentliche "Problem":
            -> Benutzer ruft Seite auf
            -> "index.php" erhält den Request

            So soll die Anwendung letztenendes (der Planung nach) funktionieren:
            - Die einzelnen Bereiche werden über das "Haupt-Config-File" registriert (ähnlich Bundels in Symfony)
            - Die Bereiche registrieren die von Ihnen zu handelnden Routen innerhalb des Bootstrap-Vorgangs
            - Silex dispatchst den Spaß und führt z.B. beim Frontend eine weitere "Dispatcher"-Klasse aus

            Warum muss nach dem Bereich nochmal dispatched werden?
            In der Datenbank gibt es eine Navigations-Tabelle, in dieser wird beschrieben das Menüpunkt X auf Modul 1 mit Parameter a, b und c zeigen soll. Besseres Beispiel: Der Menüpunkt Gästebuch soll auf das Modul "xyz_guestbook" zeigen und hat die Parameter "action=overview".

            Frage: Ist es eher sinnvoll im Bootstrap-Prozess des Frontend-Bereichs die Menüpunkte aus der Datenbank zu laden und daraus Routen zu bilden die direkt auf die Module zeigen oder der Umweg über einen extra / eigenen Dispatcher?

            -----

            Im Admin-Bereich ist es nicht ganz das selbe, hier will ich eigentlich darauf hinaus, das im Bootstrap-Prozess die Routen der Module gesammelt und dann registriert werden d.h. kein Umweg erneut über einen extra Dispatcher.

            Vielen Dank für eure Unterstützung
            Gruß,
            SebTM

            Kommentar


            • #7
              Hallöchen,

              Zitat von SebTM Beitrag anzeigen
              Vielen Dank schonmal an @lottikarotti für die ausführliche Antwort und das Beispiel. Ich ging davon aus das die Projektstruktur bzw. Verzeichnisstruktur zum größten Teil in die Kategorie "Softwarearchitektur" gehört - daher hatte ich das so geschrieben.
              Sicherlich ist eine gute Verzeichnisstruktur förderlich. Softwarearchitektur beschreibt meiner Meinung nach aber vielmehr grundlegende Abläufe und die Art und Weise wie Komponenten miteinander funktionieren / kommunizieren.

              Zitat von SebTM Beitrag anzeigen
              Dein Beispiel sieht für mich sehr interessant aus - ich habe mir hier schon einige Überlegungen gemacht, wie ich die Vorteile für mein Projekt adaptieren kann. Wo ich noch nicht ganz durchsteige, was meinst du mit Unterteilung in "Komponenten" bzw. "Features"?
              Es gibt viele Möglichkeiten wie du deinen Quellcode organisieren kannst. Eine gängige Variante ist die Unterteilung in Controller, Models, Views, .. das sähe dann quasi so aus:

              Code:
              + src/
                + Controller/
                  ErrorController.php
                  IndexController.php
                  UserController.php
                  ..
                + View/
                  ErrorView.php
                  IndexView.php
                  UserView.php
                  ..
                + Model
                  User
                  ..
              Ab einer gewissen Komplexität, also Anzahl an Controllern, Views, usw. wird das allerdings ein wenig unübersichtlich. Deshalb packe ich zusammengehörige Dateien gerne in eigene Modul-Verzeichnisse:

              Code:
              + src/
                + index/
                  IndexController.php
                  IndexView.php
                  ..
                + users/
                  UserController.php
                  UserView.php
                  UserModel.php
                  ..
              Das ist natürlich nur ein grobes Beispiel. Wonach du deine Komponenten gliederst hängt ganz von deinen Anforderungen ab. Im Prinzip ist das aber ein simples Bundle-System.

              Zitat von SebTM Beitrag anzeigen
              Villeicht ist hier mein Projekt bzw. dessen Aufbau das eigentliche "Problem":
              -> Benutzer ruft Seite auf
              -> "index.php" erhält den Request
              Darin sehe ich kein Problem. Das ist doch mittlerweile ein Quasi-Standard.

              Zitat von SebTM Beitrag anzeigen
              So soll die Anwendung letztenendes (der Planung nach) funktionieren:
              - Die einzelnen Bereiche werden über das "Haupt-Config-File" registriert (ähnlich Bundels in Symfony)
              - Die Bereiche registrieren die von Ihnen zu handelnden Routen innerhalb des Bootstrap-Vorgangs
              - Silex dispatchst den Spaß und führt z.B. beim Frontend eine weitere "Dispatcher"-Klasse aus

              Warum muss nach dem Bereich nochmal dispatched werden?
              In der Datenbank gibt es eine Navigations-Tabelle, in dieser wird beschrieben das Menüpunkt X auf Modul 1 mit Parameter a, b und c zeigen soll. Besseres Beispiel: Der Menüpunkt Gästebuch soll auf das Modul "xyz_guestbook" zeigen und hat die Parameter "action=overview".

              Frage: Ist es eher sinnvoll im Bootstrap-Prozess des Frontend-Bereichs die Menüpunkte aus der Datenbank zu laden und daraus Routen zu bilden die direkt auf die Module zeigen oder der Umweg über einen extra / eigenen Dispatcher?
              Mach dir das Ganze doch nicht so kompliziert. Ich packe meine Routen-Konfiguration immer in eine PHP-Datei (routes.php) und definiere dort alle für die Anwendung relevanten Routen. Je nach Komplexität kann man diesen Part auch in die einzelnen Module auslagern - also eine routes.php pro Modul. Eine Route beschreibt welche Aktion beim Aufruf durchgeführt wird, welche Parameter dafür notwendig sind und welchen Regeln sie unterliegt (HTTP-Methode, Access Control, Authentifizierung, ..). Kommt ein Request rein, wird dieses durch den Matcher gejagt und der Dispatcher ruft die passende Controller-Methode auf. Das Ergebnis wird in ein Response verpackt und ausgegeben. Fehler werden über Exceptions gesteuert. Ich verweise hierbei immer gerne auf diesen Beitrag von mir: http://www.php.de/821804-post42.html

              -----

              Zitat von SebTM Beitrag anzeigen
              Im Admin-Bereich ist es nicht ganz das selbe, hier will ich eigentlich darauf hinaus, das im Bootstrap-Prozess die Routen der Module gesammelt und dann registriert werden d.h. kein Umweg erneut über einen extra Dispatcher.
              Hier lautet die Devise: keet it simple stupid. Pack die Routen in eine Konfiguration ähnlich der oben genannten und lege dort alles weitere fest.

              Viele Grüße,
              lotti

              Kommentar


              • #8
                Ich setze auch immer stärker auf die Modularisierung meiner Projekte bis hin zur Auslagerung einzelner Komponenten via Composer. Ich spiele dabei auch gerade etwas mit Puli rum.
                Standards - Best Practices - AwesomePHP - Guideline für WebApps

                Kommentar


                • #9
                  Zitat von rkr Beitrag anzeigen
                  Ich setze auch immer stärker auf die Modularisierung meiner Projekte bis hin zur Auslagerung einzelner Komponenten via Composer. Ich spiele dabei auch gerade etwas mit Puli rum.
                  Sieht cool aus. Werde ich mir mal ansehen. Danke für den Link.

                  Kommentar


                  • #10
                    Projekt-Konzept & Struktur

                    Puli sieht tatsächlich interessant aus. Ich tendiere je länger je mehr auch dazu, Komponenten auszulagern. Ab nach Packagist (interne Installation) und dann wird das warten (und verteilen der aktualisierten) der Komponenten viel einfacher.
                    GitHub.com - ChrisAndChris - RowMapper und QueryBuilder für MySQL-Datenbanken

                    Kommentar


                    • #11
                      Hallo,

                      also was ich jetzt verstanden habe ist, das ich Projektunabhängige Libaries welche bei mir im "src/"-Ornder liegen wie z.B. eine Config-Klasse welche Einstellungen via Setter und Getter verwaltet in eigene Packages als Composer-Packet auslagern soll. Das macht für mich auch Sinn, weil diese Libaries wiederverwendwar sein sollen und ggf. auch Updates für alle Projekte "ausrollbar".

                      Mach dir das Ganze doch nicht so kompliziert. Ich packe meine Routen-Konfiguration immer in eine PHP-Datei (routes.php) und definiere dort alle für die Anwendung relevanten Routen. Je nach Komplexität kann man diesen Part auch in die einzelnen Module auslagern - also eine routes.php pro Modul. Eine Route beschreibt welche Aktion beim Aufruf durchgeführt wird, welche Parameter dafür notwendig sind und welchen Regeln sie unterliegt (HTTP-Methode, Access Control, Authentifizierung, ..). Kommt ein Request rein, wird dieses durch den Matcher gejagt und der Dispatcher ruft die passende Controller-Methode auf. Das Ergebnis wird in ein Response verpackt und ausgegeben. Fehler werden über Exceptions gesteuert. Ich verweise hierbei immer gerne auf diesen Beitrag von mir: http://www.php.de/821804-post42.html
                      Trotz deiner Erklärung und des Beispiels im Link komme ich damit nicht ganz klar. Irgendwie komm ich mir gerade wie der "dumme Hauptschüler" vor

                      Mein Plan ist es das Bereiche nur über einen Punkt in der Anwendung "angekoppelt" sind und alles weitere in den Bereichen selbst passiert. Das bedeutet, das in dem (s.o.) "Main-Config-File" der Bereich "Frontend" registriert wird und dann automatisch dessen Bootstrap ausgeführt wird und daher auch in diesem Zug die dort definierten Routen geladen werden müssten. Ich erhoffe mir daraus gewisse Bereich sehr leicht wiederverwenden zu können und auch durch andere (z. B. komplett neue Version) ersetzten zu können da diese nicht weiterführend "verbundelt" sind.

                      Ich stell dir Frage nochmal weil Sie mir (für mich) irgendwie "wichtig" erscheint:
                      Ist es sinnvoller eine Abstrakte Route alla "/{slug}-{id}/" zu machen oder sollte ich die vorhandenen Seiten als Route im Bootstrap-Prozess "bereitstellen" d.h. alle Seiten durchloopen während des Bootstraps des Bereichs Frontend? Für mich schein zweiteres eher unperformant - vorallem bei vielen Seiten - richtig?

                      Ab einer gewissen Komplexität, also Anzahl an Controllern, Views, usw. wird das allerdings ein wenig unübersichtlich. Deshalb packe ich zusammengehörige Dateien gerne in eigene Modul-Verzeichnisse:
                      Das ist Prinzipell meine Planung bei den Modulen welche dann je nach ID im Frontend bzw. nach Route im Backend ausgeführt werden.

                      Darin sehe ich kein Problem. Das ist doch mittlerweile ein Quasi-Standard.
                      Das war nur der Vollständigkeit halber - das war mir quasi klar

                      Ich spiele dabei auch gerade etwas mit Puli rum.
                      Ich verstehe den Sinn von Puli nicht so wirklich - gerade das Beispiel des "twig"-Templates zeigt mir doch das es gerade bei Symfony super gelöst ist?
                      Gruß,
                      SebTM

                      Kommentar


                      • #12
                        Hallöchen,

                        Zitat von SebTM Beitrag anzeigen
                        Trotz deiner Erklärung und des Beispiels im Link komme ich damit nicht ganz klar. Irgendwie komm ich mir gerade wie der "dumme Hauptschüler" vor
                        Dann lass es uns ganz simpel versuchen. Du hast eine gewöhnliche Routen-Konfiguration. Dort stehen Dinge drin wie:
                        Code:
                        return[
                            'GET /users' => [
                                'controller' => 'App\UserBundle\UserCtrl::findAll',
                                'format' => 'json'
                            ],
                            'GET /users/{id:int}' => [
                                'controller' => 'App\UserBundle\UserCtrl::findById',
                                'format' => 'json'
                            ]
                            ..
                        ];
                        Wenn nun ein Request eingeht (/users/5) wird die Routen-Konfiguration in den Router geladen, der Matcher sucht die passende Route heraus und der Dispatcher löst die Controller-Action aus. Diese liefert wiederum ein Ergebnis, welches zu einem HTML-, XML-, JSON-, .. Response umgewandelt und zum Client gesendet wird. Das machst du nun für alle Routen die deine Anwendung zur Verfügung stellt. An dieser Stelle wird gewissermaßen alles miteinander verdrahtet.

                        Zitat von SebTM Beitrag anzeigen
                        Ich stell dir Frage nochmal weil Sie mir (für mich) irgendwie "wichtig" erscheint:
                        Ist es sinnvoller eine Abstrakte Route alla "/{slug}-{id}/" zu machen oder sollte ich die vorhandenen Seiten als Route im Bootstrap-Prozess "bereitstellen" d.h. alle Seiten durchloopen während des Bootstraps des Bereichs Frontend? Für mich schein zweiteres eher unperformant - vorallem bei vielen Seiten - richtig?
                        Ich bin mir nicht sicher ob ich deine Frage richtig verstanden habe. Wenn du die Routen-Konfigurationen über die Module verteilst, musst du diese natürlich auch wieder einsammeln. Allerdings lässt sich dieser Vorgang ja auch cachen.

                        Da du selbst immer wieder von einer Trennung zwischen Frontend und Backend sprichst, frage ich mich natürlich, wieso du daraus nicht zwei Anwendungen machst? Die gemeinsam genutzten Komponenten lagerst du einfach aus.

                        Viele Grüße,
                        lotti

                        Kommentar


                        • #13
                          Hallo,

                          danke nochmals für die eingehende Erklärung jetzt geht mir teilweise "ein lichtlein auf".

                          Ich bin mir nicht sicher ob ich deine Frage richtig verstanden habe. Wenn du die Routen-Konfigurationen über die Module verteilst, musst du diese natürlich auch wieder einsammeln. Allerdings lässt sich dieser Vorgang ja auch cachen.
                          Jaein, du hast mich insofern richtig verstanden das ich die Routen innerhalb der Bereiche / Module vorhalten will. Was meine Frage angeht nicht ganz - es gibt zwei Möglichkeiten die Routen zu definieren:

                          I) Ich mache eine "abstrakte" Route mit Platzhaltern z.B. "/{slug}-{id}/" und schicke dann den Code durch einen weiteren Dispatcher um die Daten der Seite zu ermitteln und das korrekte Modul auszuführen

                          II) Ich lade an dem Punkt X wo mein Routing für diesen Bereich definiert wird alle Seiten und füge für jede Seite eine Route hinzu z.B. "/home-1/", "testseite-2", "kontakt-25" ...

                          Zweiteres kann natürlich bei einer größeren Anzahl an Seiten unperformant werden - allerdings kann man das super Cachen -> was wiederrum bei I) nicht geht allerdings würden hier die Abfragen "live" via DB stattfinden.

                          verstehst du jetzt meinen Ansatz wo ich mich entscheiden muss?

                          -----

                          Da du selbst immer wieder von einer Trennung zwischen Frontend und Backend sprichst, frage ich mich natürlich, wieso du daraus nicht zwei Anwendungen machst? Die gemeinsam genutzten Komponenten lagerst du einfach aus.
                          Als ich die Idee von dir gelesen habe dachte ich mir - ja eigentlich gut - andererseits habe ich insofern dann doppelten "Aufwand" weil die Config-Files viele Werte beinhalten welche beide Teile der Seite Frontend sowie Backend benötigen u.a. MySQL-Zugangsdaten, Swiftmailer-Config sowie Anwendungskonfigurationen. Wie würdest du das lösen? Config via DB und nur Datenbank-Zugangsdaten als file-based"?
                          Gruß,
                          SebTM

                          Kommentar


                          • #14
                            Zitat von SebTM Beitrag anzeigen
                            Ich verstehe den Sinn von Puli nicht so wirklich - gerade das Beispiel des "twig"-Templates zeigt mir doch das es gerade bei Symfony super gelöst ist?
                            Ist auch nicht so schnell erklärt, wenn es beim Gegenüber nicht auf Anhieb Klick macht.

                            Ich versuche es trotzdem mal. Nehmen wir den Klassiker: Benutzerverwaltung. Wie schön wäre es, wenn man eine fertige Benutzerverwaltung hätte, bei der man nur noch ein, zwei Adapter und ein wenig CSS schreiben müsste und dann eine nahtlose Integration in ein neues Projekt hätte? Es gibt beliebig viele Möglichkeiten mehr oder weniger vollständige Komponenten mit eigener View-Schicht und evtl. sogar eigenen Assets darzustellen, denkt man nur mal an die Möglichkeiten, die einem WebComponents (heute schon: Polymer, AngularJS-Direktiven) bieten werden.
                            Standards - Best Practices - AwesomePHP - Guideline für WebApps

                            Kommentar


                            • #15
                              Hallo rkr,

                              danke für die Erklärung - grob hab ich den Sinn des ganzen nun verstanden werde mir das bei Zeit mal genauer ansehen. Ich hoffe sobald ich mich damit wirklich mal intensiver beschäftigen kann - steige ich da ganz durch

                              Vielen Dank
                              Gruß,
                              SebTM

                              Kommentar

                              Lädt...
                              X