T-Rex: Trennung der Anliegen (Logik - Layout)

Hallo,

heute brauche ich ein paar Gedanken von euch zum Thema Trennung der Anliegen.
Bei meinem aktuellen Projekt versuche ich strikt die Logik vom Layout zu trennen. Bis jetzt habe ich auch nur Sachen die man Anzeigen muss. Sprich Daten aus der Datenbank holen, für die Ausgabe aufbereiten und ausgeben. Das ganze natürlich ganz sauber mit Template Engine.
Jetzt komme ich jedoch zum ersten Eingabe Formular. Der erste Versuch das Sauber um zu setzen ist gescheitert, da sich wie ich finde die Anliegen vermischen (dazu gleich mehr).
Mein Ansatz ist die Vorstellung das ein doofer Webdesigner (der keine Ahnung vom Programmieren hat) eine Dokumentation vor sich hat, die ihm alle Template Variablen und Möglichkeiten zeigt. Er muss sich also nur ums HTML und eventuell ein bisschen Javascript kümmern -> die Anzeige einfach. Dem zu Folge darf es Ihn auch nicht interessieren wie die Eingabefelder heißen. Das sieht dann nach meiner momentanen Vorstellung so aus:
<input type='text' name='{template_variable_name}' value='{template_variable_value}' />
Soweit so sauber.
Dieses input Feld möchte der Webdesigner jetzt jedoch als checkbox umsetzen. Dann bräuchte man jetzt noch eine Variable.
<input type='text' name='{template_variable_name}' value='{template_variable_value}' {template_variable_checked} /> (könnte man auch mit Javascript setzen, dann wäre der Wert von "template_variable_checked" egal, dann ist nur noch die Frage wichtig ob da was drin steht)
Auf jeden Fall haben sich jetzt die Anliegen wie ich finde vermischt. Die Programmlogik muss wissen ob es sich um eine Checkbox handelt oder nicht. Und das war jetzt nur ein einfaches Beispiel.
Bei einer Selectbox müsste man die richtie <option> selectieren. Somit muss die Programmlogik wissen ob es eine Selectbox ist und zudem welche <option>'s es gibt.
Bei Radiobuttons bekommt man ein Array in die Programmlogik...

Eine lange Erklärung und eine einfache Frage:
Kann man die Anliegen überhaupt sauber trennen?

Gruß
T-Rex

  1. hi,

    Bei Radiobuttons bekommt man ein Array in die Programmlogik...

    Wieso eigentlich nur bei Radiobuttons? Ein Array ergibt sich auch, wenn es mehrere Input-Text-Felder mit gleichem Namen gibt, mehrere Checkboxen, mehrere Textareas und überhaupt mehrere Eingabefelder mit gleichem Name-Attribut und nicht vergessen das Attribut multiple.

    Nurmalso nebenbei ;)

    Hotti

    1. Hallo Hotti,
      dein Post erinnert mich an einen Witz:
      ___________________________
      Ein Mann in einem Heißluftballon hat die Orientierung verloren. Er geht tiefer und sichtet eine Frau am Boden. Er sinkt noch weiter ab und ruft:

      "Entschuldigung, können Sie mir helfen? Ich habe einem Freund versprochen, ihn vor einer Stunde zu treffen - und ich weiß nicht wo ich bin."

      Die Frau am Boden antwortet:
      "Sie sind in einem Heißluftballon in ungefähr 10m Höhe über Grund. Sie befinden sich auf dem 49. Grad, 28 Minuten und 11 Sekunden nördlicher Breite und 8. Grad, 28 Minuten und 58 Sekunden östlicher Länge."

      "Sie müssen Ingenieurin sein", sagt der Ballonfahrer.

      "Bin ich", antwortet die Frau - "woher wissen Sie das??"

      "Nun", sagt der Ballonfahrer - "alles was sie mir sagten ist technisch korrekt, aber ich habe keine Ahnung, was ich mit Ihren Informationen anfangen soll und Fakt ist, dass ich immer noch nicht weiß, wo ich bin. Offen gesagt, waren Sie keine große Hilfe. Sie haben höchstens meine Reise noch weiter verzögert."

      Die Frau antwortet: "Sie müssen im Management tätig sein."

      "Ja", antwortet der Ballonfahrer - "aber woher wissen Sie das??"

      "Nun", sagt die Frau - "Sie wissen weder wo Sie sind, noch wohin Sie fahren. Sie sind aufgrund einer großen Menge heißer Luft in Ihre jetzige Position gekommen. Sie haben ein Versprechen gemacht, von dem Sie keine Ahnung haben, wie Sie es einhalten können und erwarten von den Leuten unter Ihnen, dass sie Ihre Probleme lösen. Tatsache ist, dass Sie nun in der gleichen Lage sind, wie vor unserem Treffen, aber merkwürdigerweise bin ich jetzt irgendwie schuld!"
      _______________________________

      Irgendwie hast du mir kein Stück geholfen, aber ich hab das Gefühl als ob ich keine Ahnung hätte :D.

      Gruß
      witzelnder
      T-Rex

      1. hi,

        Irgendwie hast du mir kein Stück geholfen, aber ich hab das Gefühl als ob ich keine Ahnung hätte :D.

        Hehe, mach keine Witze ;)

        Meine Hilfe besteht darin: Arrays können sich mit jedem Eingabefeld ergeben, auch mit <input type="text">, davon mache ich gelegentlich Gebrauch.

        Wenn Formulare automatisiert erzeugt werden sollen, wo die Namen der Eingabefelder mit den Feldnamen einer Tabelle übereinstimmen sollen, brauchen wir eine gemeinsame Datenquelle, worin das alles definiert ist (ok, das wissen wir auch schon *G).

        Was jedoch auch zu überlegen ist: Evntl. ist ein Object Relational Mapping (ORM) der Aufgabe besser entsprechend.  Du hast es dann nur noch mit Objekten zu tun, wo und wie die Daten abgelegt sind, ist Sache des ORM. Die OID (Object ID) ist dann das Formular und die Eingabefelder/Werte sind die Attribute.

        Viele Grüße,
        Hotti

        1. Was jedoch auch zu überlegen ist: Evntl. ist ein Object Relational Mapping (ORM) der Aufgabe besser entsprechend.  Du hast es dann nur noch mit Objekten zu tun, wo und wie die Daten abgelegt sind, ist Sache des ORM. Die OID (Object ID) ist dann das Formular und die Eingabefelder/Werte sind die Attribute.

          Das würde bedeuten, dass es für jedes Datenbankfeld eine Eingabemöglichkeit gibt? Das ist mir jedoch zu statisch. Eventuell ergibt sich ein Datenbankfeldwert aus 2 Eingaben. Feld1 + Feld2 = Datenbankfeld.
          Bei meinem Beispiel (<input type='text' name='{template_variable_name}' value='{template_variable_value}' />) ist {template_variable_name} nicht zwangläufig der Name einer Datenbankspalte. Es ist lediglich der Name um später im $_GET oder $_POST wieder auf die Sachen zugreifen zu können. Mit der Methodik kann der doofe Webdesigner (denn es wirklich nur in der Theorie gibt) nichts beim Namen falsch machen.
          --------Abschweif-----
          Bei meinem alten Arbeitgeber war das eines der Hauptprobleme. Der Value wurde per Variable gesetzt aber wie das Feld heißen muss wurde manchmal zu einer Achterbahnfahrt durch den Quellcode.
          Ich hoffe daraus was gelernt zu haben
          --------Abschweif Ende-----

          Gruß
          abschweifender
          T-Rex

          1. hi T-Rex,

            --------Abschweif-----

            warum nicht mal abschweifen ;)

            ORM: Da habe ich eine total abgefahrene Tabelle:

              
            objects	CREATE TABLE `objects` (  
              `oid` varchar(100) NOT NULL DEFAULT '',  
              `att` varchar(100) NOT NULL DEFAULT '',  
              `val` longtext,  
              PRIMARY KEY (`oid`,`att`),  
              FULLTEXT KEY `val` (`val`)  
            ) ENGINE=MyISAM DEFAULT CHARSET=utf8  
            
            

            Die Tabelle ist natürlich alles Andere als normalisiert: Die Attribute liegen übereinander anstatt nebeneinander in Feldern, das macht die Sache interessant für Objekte, die verschiedene Anzahlen an Attributen haben und dazu noch verschiedene Namen der Attribute. Dazu gibt es eine Tie-Klasse in Perl:

              
              tie my %obs, 'ORM';  # binde einen %hash an die Objektsammlung  
              my $home = $obs{'/'}; # ziehe ein Object heraus  
              $home->{title} = 'Ein neuer Titel für die Startseite';  
            
            

            Das hat jetzt auf den ersten Blick nichts mit Deinem Anliegen zu tun, ist aber ein Beispiel dafür, wie sich Aufgabenbereiche trennen lassen ohne den Code zu ändern: Eine andere Klasse 'Objects' bindet dieselbe Objektsammlung an eine Datei. Die Klasse wird austauschbar, die Datenstruktur ist dieselbe.

            Die Logik freilich, die ist immer irgendwie in den Code geschrieben. Anstelle von Templates bevorzuge ich sog. Funktionstypen (Rollen). Gerne benutze ich für das User-Interface eine Konfigurationsdatei nach dem Stil einer 'system.ini', das Format passt gut auf das Objektmodell, Object-ID mit Attributen:

            [oid]
            att=foo
            isa=hier steht der Funktionstyp

            Für den Funktionstyp stehen dann mehr oder weniger verschiedene Methoden zur Verfügung, die das aus der Konfiguration heraus erstellte Objekt benutzen darf. Wenn da z.B. notiert ist: isa=loginform, wird ein Login-Formular erzeugt, mit allen Feldern, die dazu benötigt werden.

            Vielleicht konnte ich ein paar Anregungen geben,
            viele Grüße,
              Hotti

  2. Hi!

    Bei meinem aktuellen Projekt versuche ich strikt die Logik vom Layout zu trennen. Bis jetzt habe ich auch nur Sachen die man Anzeigen muss. Sprich Daten aus der Datenbank holen, für die Ausgabe aufbereiten und ausgeben. Das ganze natürlich ganz sauber mit Template Engine.

    Auch PHP wäre bereits eine Template-Engine, und damit bekommt man das Ganze auch sauber hin. Eine Template-Engine kann aber anderweitig helfen, indem sie beispielsweise einfachere Syntax und weitere Funktionalität bereitstellt.

    Jetzt komme ich jedoch zum ersten Eingabe Formular. Der erste Versuch das Sauber um zu setzen ist gescheitert, da sich wie ich finde die Anliegen vermischen (dazu gleich mehr).

    Da muss zwangsläufig ein Zusammenspiel da sein, denn jeder Datentyp hat so seine Eigenheiten, die beim Eingabeelement berücksichtigt werden müssen. Eine Freitexteingabe geht nicht mit einer Checkbox, ein boolescher Wert macht sich in einem Textfeld nicht gut, usw.

    Dieses input Feld möchte der Webdesigner jetzt jedoch als checkbox umsetzen. Dann bräuchte man jetzt noch eine Variable.

    Er kann nicht einfach so Elemente nehmen, wie es ihm beliebt, er muss die fachliche Seite berücksichtigen. Das muss aufeinander abgestimmt sein.

    Auf jeden Fall haben sich jetzt die Anliegen wie ich finde vermischt. Die Programmlogik muss wissen ob es sich um eine Checkbox handelt oder nicht. Und das war jetzt nur ein einfaches Beispiel.

    Soweit muss es nicht kommen, wenn du die Programmlogik weiter teilst. Die Geschäftslogik will eigentlich nur mit einer booleschen Information arbeiten. Die Anzeigelogik muss dann daraus die notwendigen Template-Variablen erzeugen. Die Eingabedatenlogik muss aus dem POST/GET-Daten den booleschen Wert rauslesen.

    Kann man die Anliegen überhaupt sauber trennen?

    Es gibt auch Programmiermuster, die generelle Strukturierungen beschreiben, beispielsweise Model-View-Controller (MVC). Der Controller ist die zentrale Steuerung, aber eigentlich verteilt er die Arbeiten nur. Das Model kümmert sich um die fachliche Verarbeitung und um die Datenhaltung, die View bekommt Daten und erzeugt daraus die Ausgabe. Die Aufgaben der einzelnen Teile kann man nun auch wieder aufteilen. Zum Beispiel bedient sich das Model für das eigentliche Daten-Handling einer Datenbanklogik. Mit dem Controller tauscht es nur Rohdaten aus. Die View bereitet die vom Controller bekommenen Rohdaten für das Template auf, das seinerseits den Rest macht.

    Lo!

    1. MVC ist mir durchaus ein Begriff. Nach dem Muster versuche ich es ja. Wie gesagt bislang ging das auch super.

      Er kann nicht einfach so Elemente nehmen, wie es ihm beliebt, er muss die fachliche Seite berücksichtigen. Das muss aufeinander abgestimmt sein.

      Das würde dann bedeuten in der Dokumentation steht:
      Feld1 - muss Input
      {template_variable_name}
      {template_variable_value}

      Feld2 - muss Select
      {template_variable_name}
      {template_variable_option}

      Oder...

      Soweit muss es nicht kommen, wenn du die Programmlogik weiter teilst. Die Geschäftslogik will eigentlich nur mit einer booleschen Information arbeiten. Die Anzeigelogik muss dann daraus die notwendigen Template-Variablen erzeugen. Die Eingabedatenlogik muss aus dem POST/GET-Daten den booleschen Wert rauslesen.

      Wie sieht die Template Variable dann aus?
      <label>Feld</label> {input_feld1}
      ...Vielleicht so? Da wäre das komplette Feld in einer Template Variablen. Dann kann ich aber keine CSS Klassen mehr vergeben.

      Ich glaube die erste Option wäre dann die bessere. Fakt ist glaube ich, dass man aus der Programmlogik nicht bestimmen kann was für eine Eingabemöglichkeit es sein soll, außer man baut gleich das komplette Feld zusammen. Der Webdesigner muss die Felder einfach nach ihrem Typ umsetzen, sonst funktioniert es nicht und er bekommt was auf die Finger.

      Für mehr Ideen und Anregungen bin ich gerne offen.

      Gruß
      T-Rex

      1. Hi!

        Wie sieht die Template Variable dann aus?
        <label>Feld</label> {input_feld1}
        ...Vielleicht so? Da wäre das komplette Feld in einer Template Variablen. Dann kann ich aber keine CSS Klassen mehr vergeben.

        Sieht so aus, als ob das Template-System für diese Variante nicht geeignet ist. Es sei denn, es bietet alternative Syntax-Elemente, wie beispielsweise Funktionsaufrufe: {input_feld1(class=foo)}.

        Fakt ist glaube ich, dass man aus der Programmlogik nicht bestimmen kann was für eine Eingabemöglichkeit es sein soll, außer man baut gleich das komplette Feld zusammen.

        Was genau verstehst du unter Programmlogik? Der Begriff ist mit zu allgemein gefasst. Und wenn damit aller Code abseits des Templates gemeint ist, dann ist der noch nicht gut in Teilaufgaben heruntergebrochen. Nicht die eigentliche Geschäftslogik muss die Ausgabe-/Eingabemöglichkeiten kennen, sondern die Ein- und Ausgabelogik. Daran ist jetzt nichts Verwerfliches, was gegen das Trennungsprinzip verstieße. Die einzelnen Teile der Logiken sollte nur definierte Schnittstellen bekommen und ansonsten autark arbeiten können. Dann kann man auch mal Teile problemlos austauschen.

        Der Webdesigner muss die Felder einfach nach ihrem Typ umsetzen, sonst funktioniert es nicht und er bekommt was auf die Finger.

        Wie auch immer, er muss mit dem Programmierer arbeiten, nicht ohne ihn, und schon gar nicht gegen ihn. Gilt natürlich für den Programmierer genauso.

        Lo!

        1. Sieht so aus, als ob das Template-System für diese Variante nicht geeignet ist. Es sei denn, es bietet alternative Syntax-Elemente, wie beispielsweise Funktionsaufrufe: {input_feld1(class=foo)}.

          Das ist eine Alternative! Ich glaube aber nicht dass ich diesen Weg gehen möchte :D. Das würde bedeuten, dass Teile des HTMLs in der Programmlogik zusammen gebaut werden. Das gefällt mir nicht so.

          Aber du hast recht, eine Ein/Ausgabe Logik fehlt eigentlich noch. Aber deswegen ja diese Frage mit der Hoffnung einen guten Weg zu finden diese Ausgabelogik dynamisch und effektiv zu gestallten. Es muss eigentlich für jedes Formular eine eigene Klasse geben welche die Feldnamen bereitstellt und nach einem "send" die Feldwerte vergibt.

          Programmlogik wäre für mich wirklich alles was mit der Verarbeitung zu tun hat. Also alles außer ds Template. In wie weit die Programmlogik in Controller und Model aufgeteilt wird ist nebensächlich. Mir geht es nur um die Kommunikation zwischen Programmlogik und Template. Die zwei Teile waren für mich bislang 2 Welten.

          Aber ich glaube ich hab schon eine Lösung. Wie im Vorherigen Post beschrieben hast du ja recht. Der Webdesigner muss einfach die Art des Feldes wissen. Dann gibts keine Konflikte mehr.

          Gruß
          dankender
          T-Rex

          1. Hi!

            Sieht so aus, als ob das Template-System für diese Variante nicht geeignet ist. Es sei denn, es bietet alternative Syntax-Elemente, wie beispielsweise Funktionsaufrufe: {input_feld1(class=foo)}.
            Das ist eine Alternative! Ich glaube aber nicht dass ich diesen Weg gehen möchte :D. Das würde bedeuten, dass Teile des HTMLs in der Programmlogik zusammen gebaut werden. Das gefällt mir nicht so.

            Trenne dich von einem Kompletttrennungsversuch. Du brauchst Logik zur Generierung der Ausgabe, die das Template nicht allein bewerkstelligen kann. Außerdem ist auch eine Template-Engine ein Stück Programmlogik, die dir nicht nur Teile des HTMLs sondern letztlich das gesamte HTML zusammenbaut. Da kann es nicht so problematisch sein, für die Template-Engine eine (Helper-)Funktion zu schreiben, die dir ein Stück HTML erzeugt. Die kann ja so flexibel gestaltet sein, das sie für alle Text-Input-Felder gleichermaßen verwendet werden kann. Weitere Helper kümmern sich um Checkboxen, um gruppierte Elemente, um WeißDerGeierWas. (Woher der das weiß, bleibt sein Geheimnis.)

            Es gibt auch komplexere Ausgabeelemente, wie zum Beispiel ein Datagrid (vulgo Tabelle) mit eingebauter Sortierfunktion, wenn man auf den Spaltenkopf klickt, und Details-/Editier-/Lösch-Funktionalität für jede Zeile. Die Zeile unter dem Kopf könnte vielleicht noch Eingabefelder für eine Filterung enthalten. Und unter den Grid sitzt ein Pager. Sowas kann man effizient nicht mehr allein mit einem Templatesystem zusammenbauen lassen, da braucht es dann einen (Programm-)Teil in der Ausgabelogik, der sowas zusammenstellt.

            Aber du hast recht, eine Ein/Ausgabe Logik fehlt eigentlich noch. Aber deswegen ja diese Frage mit der Hoffnung einen guten Weg zu finden diese Ausgabelogik dynamisch und effektiv zu gestallten. Es muss eigentlich für jedes Formular eine eigene Klasse geben welche die Feldnamen bereitstellt und nach einem "send" die Feldwerte vergibt.

            Mir geht es nur um die Kommunikation zwischen Programmlogik und Template. Die zwei Teile waren für mich bislang 2 Welten.

            Dazwischen vermittelt die Ausgabelogik. Oder anders betrachtet ist das Template-System neben anderen Helpern ein Teil der Ausgabelogik.

            Lo!

      2. @@T-Rex:

        nuqneH

        Dann kann ich aber keine CSS Klassen mehr vergeben.

        Das kannst du sowieso nicht. Nicht mal ohne Deppenleerzeichen. </archiv/2011/5/t204984/#m1388927> ff. Und zitat1925.

        Qapla'

        --
        Gut sein ist edel. Andere lehren, gut zu sein, ist noch edler. Und einfacher.
        (Mark Twain)
  3. Eine lange Erklärung und eine einfache Frage:
    Kann man die Anliegen überhaupt sauber trennen?

    Ja das kannst du! Du musst aber zu deiner Vorstellung (Logik - Layout) noch einen Controller hinzufügen. Teile die Logik auf in einen Controller, der die Eingaben aus dem View (Layout) entgegennimmt, und in ein Model auf, das vom Controller verändert wird.

    Dein Beispiel erinnert mich stark an Java ServerFaces. Da hast du als View die Facelets, die zimlich genauso mit Variablem arbeiten wie du es beschrieben hast, ohne dass ein Webdesigner selbst Code schreiben müsste, und die Managed-Beans (Java Objects) die als Controller zu irgendeiner Model/Geschäftslogik fungieren.

    Schlussendlich musst du dich aber dennoch mit dem Webdesigner einigen, welche Variablen vom Controller bereitgestellt werden müssen. Du kannst das View vom Controller zwar trennen, schlussendlich wird das View allerdings immer vom Controller abhängig sein. Ich wüsste jetz nicht wie man das ganz generell anderst machen könnte.

    MfG

    splinter

  4. Du könntest das auch "klassisch" lösen: PHP in HTML.
    Das hat unter anderem den Vorteil das die HTML-Auszeichnung mit einem entsprechenden Editor auch auf ihre Gültigkeit geprüft werden können.

      
    <?php  
    // EV  
      
    // A  
    ?>  
    <?php if ($result->num_rows):?>  
        <table>  
        <?php while ($row = $result->fetch_assoc()):?>  
            <tr>  
                <td><?php echo htmlspecialchars($row['konto_name'])?></td>  
                <td>  
                    <?php echo htmlspecialchars($row['id'])?>  
                    (<?php echo htmlspecialchars($row['besitzerid'])?>)  
                </td>  
                <td>  
                    <form action="index.php?view=manage_accounts" method="post">  
                        <input type  = "hidden"  
                               name  = "delete_account_id"  
                               value = "<?php echo htmlspecialchars($row['id'])?>"  
                        />  
                        <input type  = "hidden"  
                               name  = "delete_account_name"  
                               value = "<?php echo htmlspecialchars($row['konto_name'])?>"  
                        />  
                        <input type  = "hidden"  
                               name  = "delete_account_owner_name"  
                               value = "<?php echo htmlspecialchars($row['besitzer_name']) ?>"  
                        />  
                        <input type="submit" value="entfernen" />  
                    </form>  
                </td>  
            </tr>  
        <?php endwhile ?>  
        </table>  
    <?php else: ?>  
        <p>Keine Konten</p>  
    <?php endif ?>