Frontend-Architektur der oberen Ebene. Yandex Vortrag

Die Auswahl der richtigen Architektur ist ein wesentlicher Bestandteil beim Aufbau eines Front-End-Service. Die Entwicklerin Anna Karpelevich erklärte den Schülern der School of Interface Development, was Architektur ist, welche Funktionen sie erfüllt und welche Probleme sie löst. In der Vorlesung erfahren Sie mehr über die beliebtesten Architekturansätze im Frontend: Model-View- * und Flux.


- Guten Abend. Ich heiße Anya Karpelevich. Heute werden wir über die Architektur des Front-End der obersten Ebene sprechen.

Ich arbeite in Yandex.Direct. Wir machen Schnittstellen für Werbetreibende. Sie veröffentlichen Anzeigen und passen sie an. Dies ist ein sehr komplexes, interessantes System, es hat viele miteinander verbundene Komponenten, sie wachsen ineinander, sie haben gemeinsame und ihre eigene Funktionalität. "Hosen verwandeln sich in elegante Shorts." All dies muss sehr sorgfältig kontrolliert werden. Und die Architektur in unseren Anwendungen ist sehr komplex. Dies ist einer der Gründe, warum ich heute diesen Vortrag halte. Ich liebe dieses Thema wirklich.

Was ist Architektur? Tatsache ist, dass es wahrscheinlich keine Antwort auf diese Frage gibt. Oder gibt es, aber jeder hat seine eigenen. Dies ist ein sehr kontroverses Thema. Es verursacht viele Kontroversen, viele Holivars. Und vieles, worüber ich heute sprechen werde, ist meine Meinung. Teilweise wird es von meiner Arbeitsgruppe unterstützt, teils nicht sehr. Und jeder, der die Architektur seiner Anwendung schreibt, entscheidet selbst, wie und was zu tun ist.

Deshalb ist Architektur einer der kreativsten Orte in der Arbeit eines Programmierers. Deshalb beginnt unsere heutige Präsentation auch mit Kreativität.



Schauen wir uns das linke Bild an. Ich würde mich sehr freuen, wenn jemand das darauf abgebildete Gebäude erkennt. Dies ist die Kirche von Saint-Sulpice in Paris. Achten Sie auf die Türme, um dieser willen wurde diese Kirche hierher gebracht. Ich hoffe, dass sie anders sind. Sie sind ganz anders, und dafür gibt es einen interessanten Grund. Zwischen ihnen 130 Jahre Unterschied. Dann wurde der linke Turm während des Deutsch-Französischen Krieges abgerissen und wieder aufgebaut.

Warum ist sie hier? Schau dir dieses Bild an. Die Türme haben die gleiche Architektur und die gesamte Umgebung, diese Vignetten, Befestigungen und Bogenstrukturen sind unterschiedlich. Warum so? Weil der Zweck dieser Türme der gleiche ist. Keiner von ihnen war zum Beispiel ein Glockenturm. Dies sind nur Türme. In ihnen war etwas gespeichert, und alles andere war anders. Warum? Weil die Architektur dieser Türme dieselbe ist. Beide haben ein Gewölbe, nur ein Fenster, und es ist eine Lanzette. Die Fenster sind ungefähr gleich hoch. Und die Idee ist, dass Architektur, sowohl Gebäude als auch Anwendungen, eine tragende Struktur ist. Dies ist keine Vignette, kein Flackern, keine Implementierung. Dies ist der Kern. Und diese Grundlage hängt in der Regel von der Umgebung, vom Boden und vom Gebäude ab, von dem Ziel, das sich der Architekt gesetzt hat, aber fast nie von Verfeinerungen des Designs.

Das Gebäudebeispiel für das Architekturthema ist ziemlich offensichtlich. Aber das richtige Bild ist interessanter. "Architektur ist taube Musik." "Architektur ist gefrorene Musik", sagte Johann Wolfgang Goethe im 18. Jahrhundert. Goethe wusste höchstwahrscheinlich nichts über die Architektur von Gebäuden, er war ein Dichter. Und er wusste garantiert nichts über Anwendungsarchitektur. Aber er drückte eine sehr wertvolle und interessante Idee aus.

Musik existiert in Dynamik. Das ist nichts Statisches. Dies ist ein Prozess. Und so ist eine Bewerbung ein Prozess. Er hat einen Moment des Starts, er hat einen Moment der Entwicklung, wenn wir etwas mit ihm machen, arbeiten. Und er hat endlich einen Moment der Vollendung. Die Architektur der Anwendung ist zu jedem Zeitpunkt ihr Slice. In jedem Moment sollte unsere Anwendung als musikalisches Thema klar, klar, verständlich, vorhersehbar usw. sein. Andernfalls fällt alles auseinander.

Mit dieser kreativen Einführung kommen wir zu den alltäglicheren Dingen, die der Praxis des Erstellens von Anwendungen näher kommen.

Was ist Architektur und warum wird sie benötigt?



Erstens haben wir die Organisation einer großen Anzahl von Codes, auf die wir in Direct und nicht nur in Direct ständig stoßen. Es gibt so viel Code, dass Sie sich darin verlieren können. Wir wollen uns nicht im Code verlieren.

Zweitens die Verdoppelung der Funktionalität. Dies ist auch ein ewiges Problem, dem Sie immer begegnen werden, und heute wird dieses Thema der Vervielfältigung während der gesamten Vorlesung durch die rote Linie gehen. Dieselbe Funktionalität benötigen wir möglicherweise an mehreren Stellen der Benutzeroberfläche. Wenn es an mehreren Stellen benötigt wird, muss es physisch derselbe Code sein, der an mehreren Stellen verwendet wird, keine Kopie. Warum? Wir werden weiter darüber sprechen. Die Architektur sollte uns jedoch dabei helfen, das Kopieren und Einfügen zu vermeiden.

Drittens ist die Unterstützung. Es liegt auf der Hand, dass wir eine Anwendung irgendwie unterstützen müssen, und es ist ratsam, dass nicht alle Ressourcen des Teams dafür verschwendet werden.

Ändern Sie die Zusammensetzung des Teams. Es ist auch so, dass wir uns im wirklichen Leben öfter treffen, als wir möchten. Jemand kommt, jemand geht, und wenn eine Person sechs Monate damit verbringt, den Code einzugeben, ist das schlecht. Wenn das Wissen über den Code nur in einem Kopf gespeichert ist und dieses Wissen im Falle eines Verlassens sechs Monate lang weitergibt, ist dies noch schlimmer. Im Allgemeinen hilft uns die Architektur auch dabei, all dies verständlicher zu machen und den Wissensaustausch aufrechtzuerhalten.

Hinzufügen und Erweitern von Funktionen. Auch eine ganz offensichtliche Sache. Der Manager kommt zu uns gerannt und sagt, dass dies dringend benötigt wird. Und wenn Sie dazu dringend viel Zeit und Mühe aufwenden müssen, ist dies eine schlechte architektonische Lösung. Und wir brauchen das Gute.

Und schließlich Fehler. Je verständlicher und vorhersehbarer unsere Architektur ist, desto einfacher ist es, nach Fehlern zu suchen, desto weniger Fehler.

Wie kann das alles genannt werden? All dies kann als die Probleme eines komplexen Systems bezeichnet werden. Eine Anwendung ist ein komplexes System. Die Architektur hilft uns, ein Problem zu lösen.



Kurz gesagt, irgendwie. Hier ist ein Bild von Nudeln auf meiner rechten Seite. Dies passiert, wenn Sie der Architektur nicht folgen, wenn Sie sie nicht bauen, überlegen und entwerfen. Und das zweite Bild ist, was passiert, wenn die Architektur zumindest irgendwie durchdacht ist. Dies ist nicht Saint-Sulpice, aber zumindest ein Kinderdesigner, er steht fest und fällt nicht auseinander. Heute werden wir auch viel Konstruktor spielen.



Formal über all das. Architektur ist ein Weg, um die Probleme eines komplexen Systems durch Abstraktion der Implementierung von der Schnittstelle und Differenzierung der Befugnisse zwischen Codeblöcken zu lösen. Weiter werden wir diesen langen Satz im Detail analysieren.

Was zeichnet die Anwendungsarchitektur als Wissensgebiet aus? Sie hat einen bestimmten Bereich, mit dem wir arbeiten. Das heißt, es ist nichts Abstraktes, es ist eine sehr spezifische Sache. Hier ist die Aufgabe, wir wählen Architektur dafür aus und nicht, damit wir, oooh, einen interessanten architektonischen Ansatz versuchen müssen. Also nein. Sie können etwas Kleines anprobieren, aber für ein ernstes Projekt wird die Architektur ausgewählt, manchmal für ein bestimmtes Projekt zusammengestellt.

Die Geschichte des Problems, als im Allgemeinen diese Idee entstand, dass Architektur gemacht werden sollte. Ich muss sagen, dass Edsger Dijkstra, ein wunderbarer Programmierer, 1968 eine sehr außergewöhnliche Idee zum Ausdruck brachte. Er ist wahrscheinlich besser bekannt als der Autor des Dijkstra-Algorithmus, der Suche nach dem kürzesten Weg in einem Diagramm. Aber er hat tatsächlich viele bahnbrechende Ideen für seine Zeit. Und einer von ihnen ist ein Artikel, dann werde ich Ihnen einen Verweis auf die Materialien geben, Sie können lesen, es gibt nur zwei Seiten, einen kurzen Aufsatz. Es klingt wie "Operator GOTO als schädlich angesehen", in der Übersetzung "Operator GOTO - Operator des bedingungslosen Übergangs - böse". Es war der erste Gedanke, der offiziell besagt, dass wir Architektur schreiben müssen, keine Nudeln.

Diese Idee wurde bereits in den 70er Jahren von Dijkstra in Zusammenarbeit mit Parnassus und einzeln entwickelt. Das erste detaillierte Buch über Anwendungsarchitektur im Allgemeinen wurde 1996 von Mary Shaw und David Garlan geschrieben. Tatsächlich wurden solche detaillierten Bücher über Softwarearchitektur nicht genau wegen des Umfangs geschrieben, dass jedes Wissensgebiet seine eigenen architektonischen Ansätze hat, irgendwo einen, irgendwo anders populärer, etwas im Allgemeinen an einigen Stellen nicht anwendbar. Und da Architektur ein kreativer Prozess ist, finden Sie keine spezifischen Bücher zum Schreiben von Architektur. Vielleicht gab es nach 1996 nichts besonders Detailliertes zu diesem Thema.

Was sind jetzt die Anforderungen an die Architektur des Projekts? Erstens und vor allem ist in der Tat die Erweiterbarkeit erforderlich, denn wenn Ihr Projekt nicht erweitert wird, ist es tot.

Code wiederverwenden. Hier geht es um das Kopieren und Einfügen. Wenn Sie zwei Blöcke haben, die an zwei verschiedenen Stellen verwendet werden, benötigen Sie dieselbe Funktionalität, dann müssen Sie denselben Code wiederverwenden, und die Architektur sollte so sein, dass jeder Code sofort nach Bedarf übernommen und wiederverwendet werden kann .

Autoritätstrennung zwischen Codemodulen. Wir werden heute ausführlicher darüber sprechen, warum dies notwendig ist. Die Idee ist folgende: Jedes Modul, jeder Block, jeder Code muss eine bestimmte Aktion ausführen und genau eine Funktion ausführen. Und diese Funktion sollte im Titel dieser Methode, Klasse, was auch immer das sein mag, Modul platziert werden. Ein Modul - eine Funktion.

Und schließlich die Qualität der Anwendungen. Es gibt viele Dinge, die ich gerne tun würde - sowohl Zuverlässigkeit als auch Abwärtskompatibilität. In der Realität wird es wiederum für die Aufgabe ausgewählt. Irgendwo ist Abwärtskompatibilität erforderlich, damit sich in keinem Fall etwas bewegt. Irgendwo ist Zuverlässigkeit erforderlich, damit, Gott bewahre, Passwörter, PIN-Codes von Karten oder CVVs nirgendwo auslaufen. Irgendwo muss es problemlos sein, wenn es sich um einen Satelliten oder etwas anderes handelt. Wählen Sie im Allgemeinen einige wenige aus. Je mehr Sie unterstützen möchten, desto komplexer wird die Architektur.

Weiter werden wir mit Ihnen über einige Definitionen sprechen, nur über solche enzyklopädischen Dinge. Warum ist das wichtig? Weil die Terminologie in der Architektur sehr wichtig ist und wir mit Ihnen dieselbe Sprache sprechen müssen. Die Definitionen stammen größtenteils aus dem Programmierparadigma OOP. Tatsächlich haben sie sich jedoch zu anderen Paradigmen entwickelt, mit den Begriffen „Klasse, Objekt, Schnittstelle“, die sie nicht nur im Rahmen von OOP betreiben. Diese Definitionen und dieses Verständnis stammen jedoch genau aus der Welt von OOP.



Das Einfachste ist die Klasse. Was ist eine Klasse? Dies ist eine Vorlage, dies ist ein Beispiel. Zum Beispiel ist die Snake-Klasse die Klasse Snake. Wir haben mit ihr drei private Felder definiert, dh ein Feld, auf das niemand außer den Methoden der Klasse selbst zugreifen kann - die Anzahl der Ziele, die Anzahl der Schwänze und die Länge der Papageien. Wir haben den Konstruktor bestimmt, in den wir die gleichen Köpfe, Schwänze und Längen in Papageien stecken. Habe die Schlangenklasse. Alles ist einfach.



Wir gehen weiter. Objekt. Und ein Objekt ist eine Instanz einer bestimmten Struktur. Darüber hinaus wird auch in der klassischen OOP impliziert, dass ein Objekt ein Objekt einer Klasse ist. In der modernen Welt, in JavaScript, das nicht immer eine OOP-Sprache war, und selbst jetzt ist es nicht immer und überall OOP, wissen wir, dass es abstrakte Objekte geben kann. Das heißt, wir können ein Objekt erstellen, ein Literal, das kein Objekt der Klasse sein wird. Aber hier ist ein Beispiel, wie wir ein Objekt der Snake-Klasse erstellen. Hier haben wir eine zweiseitige Schlange mit einer Länge von 38 Papageien - eine Boa Constrictor.



Modul Ein Modul ist eine semantische Einheit. Dies ist nicht immer eine Klasse. Es kann sich um eine Reihe von Klassen, eine Reihe von Objekten und eine Reihe von Methoden handeln, die nicht zu Klassen zusammengefasst sind. Normalerweise können Sie davon ausgehen, dass ein Modul das ist, was Sie in eine einzelne Datei geschrieben haben. Im Prinzip ist das Modul jedoch der Ordner, in dem sie liegen. Beispielsweise sind die Datei und die Tests für dieses Modul auch ein Modul. Wichtig ist hierbei, dass ein Modul das ist, was Sie als Modul bezeichnen, was Sie als eine Einheit der Semantik betrachten. In diesem Fall geht es im Modul darum, wie wir Schlangen essen. Das Ergebnis dieses Moduls ist die letzte Methode, eatSnake, da wir Schlangen gegessen haben. Ich weiß nicht, warum wir Schlangen essen, aber wir können es tun, weil wir dieses Modul so geschrieben haben.



Es war trivial, dann wird eine etwas interessantere Sache beginnen. Klassenschnittstelle. Die Schnittstelle einer Klasse ist einfacher ihre öffentlichen Methoden, was sie hervorhebt, was wir von einem Objekt dieser Klasse von einem Objekt von außen erhalten können. Diese Klasse implementiert die getSnakeLength-Schnittstelle. Er kann uns die Länge der Schlange zurückgeben. Bitte beachten Sie, dass kein externer Zugriff auf private Felder besteht. Der Zugriff von außen erfolgt nur über die öffentliche Methode getSnakeLength.



Und dann eine sehr interessante Sache. Wir haben lange darüber gestritten, wie man das Ding nennt, weil ich bei der Erstellung dieser Vorlesung den Begriff "abstrakte Schnittstelle" geprägt habe. Und ehrlich gesagt habe ich noch nie eine normale Definition dieses Ansatzes und dieser Methode gesehen. In vielen Programmiersprachen können Sie jedoch abstrakte Schnittstellen erstellen und diese aufrufen, sobald nicht abstrakte Klassen und auch abstrakte Schnittstellen nur Schnittstellen sind. Es stellt sich ein Homonym mit der Klassenschnittstelle heraus. Die Idee ist, dass eine abstrakte Schnittstelle eine Reihe von Methoden ist, die etwas bewirken. Wenn wir eine Klasse erstellen, gehen wir von der Frage "Was ist das?" Dies ist eine Schlange und sie weiß, wie man etwas macht oder nicht. Sie kann nur ihre Länge geben.

Und wenn wir die Schnittstelle erstellen, gehen wir von dem aus, was er tut, was er tun sollte. Und dies erweist sich als eine sehr mächtige Möglichkeit, den Unterricht zu erweitern. Wir können einigen Klassen Klassen zuordnen und sie mithilfe von Schnittstellen erweitern. Zum Beispiel kann das I-BEM-Framework so etwas tun, eine solche Geschichte mit abstrakten Schnittstellen ist in das Framework integriert. Leider wissen viele Frameworks nicht wie und das Ding ist mächtig.

Hier haben wir als Beispiel die hörbare Oberfläche erstellt, die klingen kann. Und seine Definition ist die abstrakte leere getNoise-Methode. Wir haben unsere Schlange um die hörbare Klasse erweitert, ihre getNoise-Methode implementiert und unsere Schlange zischte. Die Inspiration für diese Reihe von Beispielen gab mir das wundervolle Buch von Eric Freeman und Design Patterns.

Nun werden wir versuchen, diese Beispiele etwas genauer zu betrachten.



Aber lassen Sie uns zuerst darüber sprechen, warum diese Beispiele benötigt wurden. Und sie wurden hier für diese große Rutsche gebraucht. Was hier geschrieben steht, ist so wichtig, dass ich es sogar in das gelbe Schriftfeld stecke. Es kann ein Mantra gesagt werden. Dies ist ein sehr wichtiges Prinzip, über das Sie beim Entwerfen von Architektur immer nachdenken müssen. Hohe Kohäsion, geringe Kopplung - starke Haftung, schwache Konnektivität. Es gibt ein gewisses Problem mit der Tatsache, dass das Wort Kohäsion und das Wort Kopplung ins Russische übersetzt werden und so weiter und so fort "Verbundenheit" übersetzt wird, das Wort Kopplung wurde speziell für dieses Prinzip erfunden.

Das ist die Idee. Ihre Blöcke müssen sehr kompakt und sehr eng miteinander verbunden sein. Sie müssen genau eine Funktion implementieren. Und untereinander sollten sie sehr einfach miteinander verbunden werden können, damit sie wie ein Designer leicht kombiniert und zusammengebaut werden können. Und dann ist Ihre Architektur flexibel und zuverlässig genug. Und auch einfach zu testen.

Mal sehen, wie wir eine starke Traktion und eine schwache Kopplung an den Punkten des sogenannten erreichen können.



Spezialisierung. Jeder Block löst nur ein Problem. Hier haben wir eine gute Illustration - einen Kinderdesigner. Wir haben jeden Block oder eine Reihe von Blöcken. Sie haben alle ihre Form, ihre Größe. Und wenn wir ein Haus bauen müssen, werden wir lange Bars nehmen. Wenn wir einen Ball bauen müssen, nehmen wir kurze Balken. Jeder Balken hat seine eigene Funktion. Und diejenigen, die Konstrukteure spielten, wissen: Je einfacher die Form der Teile ist, desto mehr können Sie daraus bauen. Aus einem solchen Zagogulin wird nichts gebaut, oder es wird nur das gebaut, was in der Anweisung beschrieben ist. Und wer braucht das?

Das Gleiche, Abstraktion. Hier geht es um die Abstraktion der Schnittstelle von der Implementierung. Die Idee ist, dass die Schnittstelle extern ist, wie unsere Klasse ist, unser Block hervorsticht, wie er mit anderen Blöcken interagiert, sollte seine interne Implementierung nicht beeinflussen. Im Gegenteil - es passiert. Der andere Weg - niemals. In einer guten Architektur. Hier wirkt sich beispielsweise die Bildung dieser Pickel nicht auf die Form des Blocks selbst aus. Wir wählen die Form des Blocks separat aus und kleben bereits Klebstoffe darauf.



Kapselung. Fortsetzung des vorherigen Themas. Bei privaten Methoden, dh innerhalb unserer Blöcke, erkennen wir die Bedeutung unserer Blockimplementierung. Und die Schnittstelle, wie sie verbunden sind, ist öffentlich. Das heißt, in diesem Fall sind alle diese Kreuze, Striche und das Formular selbst implementiert. Und Pickel sind die Schnittstelle. Und gute Architektur sieht aus wie ein solcher Konstrukteur.



Oh, was für ein gruseliges Monster. Hier geht es um die Wiederverwendung von Code. Eigentlich sollte dieses Monster ein Beispiel für schlechte Architektur zeigen, aber schauen Sie es sich genau an. Er ist wunderschön. Außerdem ist er eindeutig zufrieden mit seinem Leben, läuft ziemlich kräftig auf seinen seltsamen Beinen. Vielleicht kann er sogar fliegen, oder zumindest hat er wunderschöne Schmetterlingsflügel.

Was ist die Idee? Wenn Sie eine Implementierung für ein Kamel und eine Implementierung für ein Krokodil haben und ein Manager zu Ihnen kommt und sagt, dass ein Kamelkrokodil dringend benötigt wird. Sie schreiben ein Kamelkrokodil nicht separat. Sie nehmen den Körper eines Kamels und trennen ihn von der gesamten Verwirklichung des Kamels. Nehmen Sie den Kopf des Krokodils, trennen Sie ihn vom Krokodil und verwenden Sie die Blöcke wieder. Warum ist das notwendig?

Wenn dann der Manager wieder zu Ihnen rennt und sagt, dass wir dringend nach Südamerika expandieren und es Alligatoren gibt, müssen wir eine unregelmäßige Kieferform beibehalten, oder dass dort der vierte Zahn des Krokodils nicht so ist, werden Sie nicht über das gesamte Projekt herumfummeln , wo hast du die Köpfe der Krokodile kopiert? Weil Sie vielleicht ein anderes Zebra-Bison-Krokodil in der Nähe haben. Sie nehmen Ihrer Klasse einfach den Kopf eines Krokodils, machen eine Erweiterung aus der Reihe des Alligatorkopfes, geben ihm die Parameter und bestimmen selbst, welche Zähne für ihn gezogen werden sollen. Und alle. An einem Ort und nicht an allen Orten, an denen es verwendet wird.

Hier steigt die Zuverlässigkeit zeitweise, da Sie in einem sehr seltenen Projekt garantiert einen kopierten Kopf vergessen. Im Allgemeinen ist an solchen Kadern nichts auszusetzen. Guter Kader, nützlich.



- . , . TypeScript, . , . , , , TypeScript 2.7 , ( — . .).

, User. . . User , . User , , .

printLabel. User. , User User, . User User , , . - , .

, ? , . , . , − , UserWithSurname, , printLabel. ? , , , , . - ? , . , − , . . PrintLabel . ? ? , .

, . , . , , . , if, , . , , .



printLabel, , iPrintLabel , iPhone, . - getText. User, iPrintLabel. , , , - , getText iPrintLabel, , . UserWithSurname, User, Surname getText. printLabel . iPrintLabel getText.

, , , . . , , . , , , , , iPrintLabel, , , , − . printLabel . , .

. , , , front-end, , . , front-end , , .



-? . - back-end. - API, , REST API REST. — , − -. , , - PowerPoint, . .

front-end. Front-end - . - , . , - . . . , -, . , , . .

front-end, , , , , , , .

> - ( Client-server )
> ( Component-based )
> ( Event-driven )
> REST ( Representational state transfer )
> --*( MVC , MVP , MVVM )
> ( Flux )

Dies sind die architektonischen Ansätze. Einige davon haben wir heute erwähnt. Client-Server-Architektur; Komponentenarchitektur, eine ihrer Variationen ist Ihnen aus React bekannt, hoffentlich vertraut. Event, das seltsamerweise auch jedem bekannt ist, basiert auf fast allen Betriebssystemen für PCs. REST, was wir am Server lieben, und die letzten beiden, die wir heute im Detail kennenlernen werden, sind die Front-End-Modelle. Wir arbeiten mit einem Präsentationsmodell * und unidirektionalen Datenströmen.

Beginnen wir mit MV *. Warum ein Sternchen? Geschichte, wie sie sagen, voller Schmerz und Wut. Es war einmal in den 80er Jahren, als der wunderbare architektonische Ansatz von MVC erfunden wurde. M-Modell, V-Ansicht, C-Controller. Der Ansatz war sehr praktisch. Erfand es allgemein für Konsolenanwendungen. Aber als sich Webtechnologien zu entwickeln begannen, als sie alle anfingen, sie zu nutzen, stellte sich heraus, dass es manchmal notwendig war, hier ist das MV-Modell gut, aber der Controller ist nicht richtig implementiert. Infolgedessen gab es so viele verschiedene Variationen der Model-View-Implementierung - etwas, das zunächst verwirrt wurde, weil alles MVC hieß. Denn wenn es ein MV-Modell gibt, dann ist das dritte Controller, es spielt keine Rolle, was wir dort tatsächlich gestopft haben.

Dann stellte sich heraus, dass die Leute verwirrt sind und mit MVC ganz andere Dinge meinen. Vor ungefähr einem Jahr haben sie begonnen, diese Terminologie aktiv zu teilen und für jede Implementierung dieses Ansatzes ihre eigenen Namen zu vergeben. Auf die eine oder andere Weise erschien dieses MV *. Ich habe auch den Begriff MVW im Internet gesehen, wo W Was auch immer ist. Nun, wir bewegen uns tatsächlich zu MVC-Technologien.



Wie sind sie angeordnet? Die Idee ist, dass wir ein Modell haben, das Daten speichert. Es gibt normalerweise viele von ihnen. Es gibt eine Art Ansicht, die diese Daten dem Benutzer anzeigt. Sie sind in der Regel auch viele. Und eine dritte Komponente, die als Vermittler zwischen ihnen fungiert, verbindet Daten und Anzeige. Hier arbeitet der Benutzer in der oberen rechten Ecke mit all dem.



MVC, alles begann 1980, Smalltalk. Aber in dieser Form existiert es bisher in einigen Frameworks. Nicht in einigen, ganz in vielen. Was ist die Idee? Der Benutzer arbeitet direkt mit der Ansicht und dem Controller. Er gibt Daten in einige Felder der Ansicht ein, drückt die Senden-Taste und die Daten gehen an den Controller. Dies ist eine Formularübermittlung. Ich hoffe, dass solch eine ehrliche Formularübermittlung per Senden-Button jedem schon lange bekannt ist.

Wir schauen. Der gelbe Pfeil vom Benutzer zum Controller - Dies ist der Benutzer, der Daten über die Schaltfläche "Senden" an den Controller übertragen hat. Ein grüner Pfeil - die Kontrolle ging dort vorbei. Der Controller betrachtet diese Daten. Vielleicht verarbeitet er sie irgendwie, die Feinheiten der Implementierung sind bereits vorhanden und sendet sie an das gewünschte Modell. Der Controller selbst wählt das zu sendende Modell aus. Sendet einen grünen Pfeil, sendet Daten mit einem gelben Pfeil.

Das Modell verarbeitet auch Daten. Vielleicht bestätigt sie sie. Vielleicht legt sie sie in die Basis. Kurz gesagt, das Modell weiß, was mit ihnen zu tun ist. Das Ergebnis sind in der Regel neue Daten. Beispielsweise können wir dem Benutzer mitteilen, ob er sich angemeldet hat oder nicht, und das Modell hat das Kennwort mit der Anmeldung überprüft. Danach überträgt das Modell die Steuerung erneut an die Steuerung, sodass die Steuerung auswählt, welche Ansicht angezeigt werden soll. Und die Daten gehen direkt in die Ansicht. Wie kann dies im Allgemeinen erfolgen, wie kann ein Modell Daten an eine Ansicht senden?



Sehr einfach. Wenn sich der Controller und das Modell im Back-End befinden und die Vorlagenansicht serverseitig ist. Auf diese Weise werden die Frameworks für Ruby on Rails, ASP.NET und Django im Allgemeinen überall dort angeordnet, wo Sie serverseitige Vorlagen schreiben, und der gesammelte HTML-Code kommt zum Client, und die Daten gehen mit hoher Wahrscheinlichkeit auch zurück. Dies ist dieser Ansatz. Was sind die Probleme hier. In einer Anwendung mit nur einer Seite kann so etwas nicht erstellt werden. Wir haben ständig Daten auf dem Server, sind auf dem Server verschwunden, die Seite wird neu geladen. Zweitens ist nicht klar, wohin die Client-Validierung verschoben werden soll, und im Allgemeinen Client-JavaScript, AJAX und all dies hier? Denn wenn wir schnell etwas wollen, nirgendwo. Es funktioniert einfach nicht in diesem Ansatz oder funktioniert so, dass es nicht besser funktioniert.

Die letzte Zeile hier, dies ist eine so interessante Geschichte, die anscheinend im Jahr 2008 verwurzelt ist. Die Frage war: Wo soll die Geschäftslogik gespeichert werden - auf dem Modell oder in der Steuerung? Es gab Leute, die sagten: "Wir speichern die Geschäftslogik in der Steuerung, weil es praktisch ist, sofort saubere Daten an das Modell zu senden. Der Controller überprüft sich selbst, überprüft ihn gegebenenfalls erneut und sendet einen Fehler. " Es gab diejenigen, die sagten: "Das Ergebnis sind fette, dumme, hässliche Controller, dicke, dumme, hässliche Controller." Sie sind wirklich riesig geworden. Und sie sagten, dass die Geschäftslogik im Modell sein sollte und der Controller dünn und leicht sein sollte, die Daten übertragen und das Modell selbst verarbeitet werden sollte. In der ersten Version stellt sich heraus, dass das Modell im Allgemeinen nur eine API für die Datenbank ist.

Wie meiner Meinung nach wirklich? In der Tat müssen Sie ihre Aufgaben beobachten. Wenn Sie eine Verbindung zwischen einer Ansicht und einem Modell haben, die immer eins zu eins ist, ist eine Ansicht ein Modell. Dann ist es für Sie praktisch, Geschäftslogik in Controllern zu erstellen und ein einfaches, sauberes Modell zu erstellen, das tatsächlich eine API für die Datenbank darstellt. Wenn sich Ihre Ansichten und Modelle überschneiden können und eine Ansicht von vielen Modellen abhängt, funktioniert das Modell mit vielen Ansichten. Es ist praktisch, wenn Sie viele Thin Controller haben und diese in jedem Verlauf multiplizieren. Es ist Ihnen egal, wie viele es sind, sie sind immer noch klein.

Ich muss sagen, dass die Welt den zweiten Standpunkt gewonnen zu haben scheint, mit Geschäftslogik in den Modellen. Das heißt, diese fetten, dummen, hässlichen Controller scheinen nicht so aktiv eingesetzt zu werden. Signale können Sie sehen, was in der Dokumentation zu ASP.NET, dem 2013 bereits vorgeschlagenen Framework, Geschäftslogik in Controllern. Und in den neuesten Versionen 2014 - in den Modellen. Es gab einen sehr interessanten Moment, als sich dies änderte.

Welche MVC haben Probleme. Wir haben sie bereits gesprochen, aber wir werden es tun. Testen, da nicht klar ist, wie die Client-Validierung implementiert werden kann, ist möglich, aber schwierig. AJAX ist seitlich angeschraubt. Sie müssen etwas tun. Sie haben eine Lösung gefunden. Die Lösung hieß MVP, und ja, Sie können MVP im Framework mit dem Text treffen, dass es sich um MVC handelt. Zum Beispiel das Backbone MVP-Framework. Über ihn wurde lange Zeit in der Dokumentation im gleichen Zeitraum 2011-2012-2013 geschrieben, dass dies ein MVC-Framework ist.



Model-View-Presenter. Sein Schema ist schon viel einfacher. Es gibt Modelle. Sie interagieren miteinander. Sie geben Daten an Presenter weiter, Presenter überträgt sie in die Ansicht und zeigt sie dem Benutzer. Und zurück. Der Benutzer steuert etwas in die Ansicht, klickt auf die Schaltfläche, Presenter sieht aus, AJAX sendet an das Modell oder fügt es in das Modell ein, und das AJAX-Modell sendet an den Server. Das heißt, alles ist bereits viel einfacher und linearer, aber ohne serverseitige Standardisierung wird es bereits Schwierigkeiten geben. Wenn Sie einen Server möchten, ist ein solches System kompliziert.



Vergleichen wir. Schauen wir uns das erste Bild an, in dem wir versuchen werden, eine sehr einfache Sache zu implementieren - das Senden von Daten von der Eingabe an das Modell. Wir haben etwas eingegeben, auf eine Schaltfläche geklickt, es sollte im Modell erscheinen, das Modell wird etwas damit machen und uns mitteilen, dass etwas passiert ist. Wir fuhren hinein: "Mein Name ist Vasya", klickte auf OK. Wenn wir eine clientseitige Validierung wünschen, geschieht dies hier fast durch Abfangen, in besonders schweren Fällen sogar durch Abfangen eines Klicks durch event.preventDefault (). Und irgendwo verschraubte ein Punkt Null auf der Seite die Client-Validierung.

Dann senden wir ehrlich Daten über das Übermittlungsformular an den Controller. Die Daten gehen in das Modell, das Modell setzt sie in sich selbst, verarbeitet, sieht aus. Sagt uns, dass die Daten akzeptiert werden, Sie sind wirklich Vasya. Der dritte Pfeil - die Steuerung geht an die Steuerung, das Modell teilt der Steuerung mit, dass bitte die Bezeichnung „Mein Name ist Vasya“ angezeigt wird. Der Controller wählt die entsprechende Ansicht aus und zeigt die Beschriftung an. Und die Daten "Mein Name ist Vasya", der vierte Pfeil, gelb, das Modell dort platziert. Die Frage ist, wie man das testet. Nur ein Schnappschuss. Kein anderer Weg. Es gibt nichts, worüber man auch nur Funktionstests schreiben könnte.

Die zweite Option, bereits mit MVP. Wir fuhren "Mein Name ist Vasya" und klickten auf "OK". Pfeil unter Nummer eins, grün, - Management ging an Presenter. Der Moderator sagte: Taste wird gedrückt. Der Moderator sieht aus, Pfeil Nummer zwei, blau. Beachten Sie, dass dies eine Datenanforderung ist. Im klassischen MVP werden keine Daten aus der Ansicht an Presenter gesendet, sondern eine Anforderung von Presenter nach Daten. Dies ist viel sauberer, da Presenter möglicherweise bereits im Voraus weiß, dass beispielsweise keine Daten benötigt werden, obwohl alles schlecht ist.

Als nächstes ist der dritte Absatz über Presenter eine ehrliche JS-Validierung. Wir können es schon sicher schreiben, dies ist ein besonderer Ort dafür. Der vierte Pfeil - die Daten gehen an das Modell, zum Beispiel in die Datenbank, sagte: "Alles ist in Ordnung, ich habe es." Der fünfte Pfeil ist gestreift. Ich hoffe, es ist klar, dass er gelbgrün gestreift ist und die Verwaltung und die Daten an Presenter zurückgegeben wurden. Das Modell sagte "Ich habe es gesagt", Presenter erkannte, dass, da die Daten in die Datenbank gestellt wurden, es bedeutet, dass angezeigt werden muss, dass alles in Ordnung ist, die Daten werden gestellt. Und der sechste Pfeil - sie haben ihn zur Ansicht geschickt, vielleicht zu einer anderen, aber dann habe ich die zweite Ansicht nicht gezeichnet.

Was ist das Plus hier. Die JS-Validierung fiel an ihren rechtmäßigen Platz und alles wurde gut damit, AJAX fiel auch an seinen Platz. Dies kann der vierte Pfeil sein, zum Beispiel, wenn sich das Modell auf dem Server befindet oder das Modell AJAX selbst zum Server geht. Und schließlich können wir Presenter sicher testen und Funktionstests darauf schreiben.



Zweitens, was haben wir neben vereinfachten Tests noch positiv? Wir haben eine Trennung zwischen visueller Darstellung und ihrer Arbeit. Das heißt, wir können weiterhin einen Snapshot in View schreiben und Tests in Presenter separat schreiben. Wir können den Presenter reparieren und die Ansicht nicht berühren und umgekehrt. Unsere Spezialisierung hat sich verbessert. So werden Frameworks wie Angular1, Backbone, Ember, Knockout früherer Versionen angeordnet. Sobald es viele von ihnen gab, nur heftiger Wettbewerb.

Was sind die Funktionen. Presenter ist bereits auf dem Client platziert, das Modell kann dort sein, und dort werden Anwendungen für einzelne Seiten leise erstellt. Es passiert besser, aber es gibt viele einseitige Anwendungen für diese Geschichte, oder zumindest wurde dies bereits zuvor getan. Die AJAX-Serverinteraktion ist gut. Client-Validierung vorhanden. Es scheint, dass alles in Ordnung ist, warum weiter denken?

Es wurde jedoch mindestens MVVM erfunden. Auch eine interessante Sache.



Im Wesentlichen handelt es sich hierbei um eine Implementierung von Presenter unter Verwendung des Frameworks. Es stellte sich oft heraus, als Sie den ersten Moderator, den zweiten Moderator, den fünften Moderator schrieben, dass sie alle gleich sind. Und sie stricken einfach eine Ansicht und ein Modell. Wie Sie sehen können, ist es wie MVP aufgebaut.



Und so viele Frameworks haben gerade diese verbindlichen Aufgaben gelöst. Was sind die Vorteile? Wir müssen keinen zusätzlichen Code schreiben. Und es beschleunigt die Entwicklungsgeschwindigkeit wirklich. Was sind die Nachteile. Die Konnektivität zwischen Model und ViewModel wird verbessert.

Das heißt, Probleme treten dort gerade aufgrund der starken Verbundenheit auf, so dass es manchmal vorkommt, dass MVVM nicht verwendet wird. Zum Beispiel bin ich persönlich mit MVVM im i-BEM-Framework vertraut, das wir manchmal verwenden und manchmal nicht verwenden, weil es eine unbequeme, zu enge Bindung ist. Es gibt jedoch Microsoft Silverlight, das von dieser Technologie organisiert wird, und sie sagen: gut. Ich weiß nicht, ich habe es nicht versucht.

Warum ist es passiert, dass neben MVP und MVVM noch etwas anderes aufgetaucht ist, das Sie alle mit dem Wort Redux vertraut haben, warum es unidirektionale Datenströme gab.



Wir sehen uns das richtige Bild an. Wir mit MVP haben regelmäßig ein solches Problem. Angenommen, wir haben ein komplexes System, nicht eins zu eins - viele Ansichten, viele Modelle. Sie sind alle miteinander verbunden. Die gelbe Ansicht von oben veränderte das Modell. Das Modell hat ein anderes Modell geändert. Die untere gelbe Ansicht hat sich geändert. Die untere Ansicht änderte auch das Modell. Alle zusammen haben die zentrale rote Ansicht verändert, und etwas Unverständliches passiert darin.

Facebook sah sich damit konfrontiert, als sie ständig einen Fehler aufgrund ungelesener Popup-Nachrichten bekamen. Das heißt, der Benutzer sieht "Sie haben eine ungelesene Nachricht", wird geöffnet, dies ist jedoch nicht der Fall. Weil die beiden Ansichten zusammen den Zustand dieser Ansicht korrigierten ... Im Allgemeinen wurde der Zustand der Ansicht aus zwei verschiedenen Quellen korrigiert, und wer Recht hat, ist nicht klar. Sie regierten es, ein Fehler trat wieder auf, sie regierten erneut, ein Fehler trat erneut auf. Am Ende waren sie müde und beschlossen, das Problem radikal zu lösen, die Tautologie zu entschuldigen und den Ansichtszustand nur deterministisch zu machen.

Das Problem von MVP liegt genau im Nichtdeterminismus des Zustands des Systems. Wir können nicht immer vorhersagen, in welchem ​​Zustand sie sich jetzt befindet und wer zuerst dort war, wer was korrigiert hat. Flux hat dieses Problem, wie man so sagt, genetisch gelöst. Das kann er nicht haben. Sie sagten mir hier lange, dass die Idee mit einem unidirektionalen Datenstrom in der Luft lag, das stimmt. Und dieses Konzept wurde natürlich lange vor Facebook erfunden, lange vor 2013, als sie es veröffentlichten. Aber sie haben, wie sie sagen, patentiert, sie haben zuerst einen Spreadshit veröffentlicht, dass wir uns so etwas ausgedacht haben, benutze es.



Schauen wir uns Flux genauer an. Hier ist die Idee. Wir haben ein Geschäft, und dieses Geschäft ist ein Data Warehouse. Dies ist die einzige Quelle der Wahrheit für unsere Anwendung. Alles andere ist falsch. Wie arbeitet er? Wenn wir uns den Arbeitszyklus genauer ansehen, beginnt er normalerweise damit, dass der Benutzer etwas tut, dh die Ansicht funktioniert. Ansicht erstellt eine Aktion. Bitte beachten Sie, dass die Aktion nicht im Bild ausgefüllt ist. Warum so? Weil es eine Struktur ist. Dies ist keine Klasse, kein Objekt, es ist nichts Kluges. Das ist die Struktur. Im Web können wir es in JavaScript schreiben, es ist nur dieses sehr abstrakte Objekt.

Die Ansicht erstellt eine Struktur und wird an den Blockmanager übergeben. Der Blockmanager löst einen Rückruf aus. Das heißt, er sagt: „Rufen Sie die Funktion auf, die ich aufrufen soll, wenn die Aktion ausgeführt wird. Er sagte, er soll den Laden anrufen. " Das heißt, die Store-Methode wird vom Dispatcher aufgerufen. Die Methode wird aufgerufen. Die Methode wird aufgerufen und im Store bezogen. Der Store schaut sich an, was dazu gekommen ist, verändert sich irgendwie von selbst. Er ändert seinen Zustand. Und er ist der einzige, der seinen Zustand ändern kann. Das macht sonst niemand. Das heißt, er ist die einzige Quelle der Wahrheit. Danach sendet es an alle damit verbundenen Ansichten, alle damit verbundenen Komponenten: "Ich habe mich geändert, holen Sie sich die Daten."

Die Ansichten beziehen sich auf Daten, und dann beginnt ein interessanter Moment. Im klassischen Flux, wie es auf Facebook ist, wird die Ansicht komplett neu gezeichnet.



Hier ist unser Formular mit einem Etikett und einem Knopf. Wie arbeitet sie? Wir schauen auf Punkt Null. Punkt Null ist auch hier. Er ist der blaue Pfeil ganz unten, Rückrufregistrierung. Das passiert zuerst.

Der Filialleiter ruft an: "Bitte registrieren Sie meinen Rückruf. Was werde ich tun, wenn Action zu Ihnen kommt?" Es ist passiert. Dann können wir mit der Anwendung arbeiten. Wir haben auf eine Schaltfläche geklickt und eine Struktur erstellt. Bitte beachten Sie, dass Action zusätzlich zu den vom Benutzer eingegebenen Daten, z. B. Vasya, auch Metadaten vom Typ hat. Ein sehr wichtiger Punkt ist, dass die Aktion selbst vermittelt, um welche Art von Aktion es sich handelt, aber trotzdem an den Disponenten. Er wirft die ganze Action-Sendung. Erster Pfeil, die Methode wird aufgerufen.

Der Dispatcher ruft die Methode tatsächlich als Aktionstrigger auf und übergibt diese Aktion dort. Am Action-Trigger wird ein Rückruf aufgerufen, den wir am Punkt Null registriert haben. Hier ist der rote Pfeil, dies ist ein Rückruf von einem Rückruf. Der Store nimmt diese Daten, sieht so aus, als wäre der Typ "Name ändern", also ändere ich mich im Namensfeld in "Vasya" und sende sie an das Back-End und validiere irgendwie, wahrscheinlich im Allgemeinen, dass der Store weiß, was zu tun ist . Als nächstes überträgt der lila Pfeil das Änderungsereignis. Wir haben uns verändert. Jeder weiß, dass wir den Store geändert haben.

Als nächstes ein kleines Feature des klassischen Flux, das denjenigen, die mit Redux gearbeitet haben, möglicherweise unbekannt ist, genauer gesagt, sogar mit React und nicht mit Redux. Ansichten gehen für Daten. Sie gehen in den Laden und sagen: "Ich habe dieses Feld, dieses Feld und dieses Feld." Wir sind daran gewöhnt, dass im Gegenteil alles zu den Ansichten kommt, wenn Sie mit React, Redux oder so etwas gearbeitet haben. Und der sechste Punkt, ein komplettes Neuzeichnen.

Schauen wir uns dieses Diagramm an und finden einen Engpass, wegen was? Neu zeichnen. Eine vollständige Neuzeichnung, weshalb Flux nach 2013 aktiv genutzt wurde. Wann ist was entstanden? Was hat das möglich gemacht? Virtuelles Haus. Ein virtuelles Haus, mit dem Sie nur dann neu zeichnen können, wenn es wirklich notwendig ist.



Lassen Sie uns beiseite treten und über React sprechen, das auf diese Weise, sehr erfolgreich in Kombination mit Flux, die Welt geschaffen hat, die wir jetzt kennen, wenn diese Technologie am beliebtesten ist.

Das gleiche 2013, das gleiche 2013, das gleiche Facebook. Ursprünglich wurde React im Allgemeinen als Hinweis auf Ansichten in MVC-, MVP- und Variationen erfunden. Und es kann tatsächlich dort verwendet werden. Was ist seine Kraft. Erstens erlaubt das virtuelle Haus, wie sie richtig sagten, das reale Haus nicht neu zu zeichnen, da es eine sehr schwierige Operation ist, sondern das virtuelle Haus neu zu zeichnen. Und nur wenn sich tatsächlich etwas geändert hat, zeichnen wir die Komponente neu, wodurch alles viel schneller funktioniert, als es sein könnte.

Und - reine unveränderliche Komponenten. Dies ist der Eigenschaftenmechanismus. Die Implementierung ist auch reaktiv, sodass Sie Komponenten erstellen können, die keinen eigenen Status haben. Und wenn Sie in diese Architektur schreiben, ist es sehr richtig, Komponenten sauber, ohne Status, ohne Status zu erstellen. Sie haben nur Daten, die aus dem Laden stammen, und er zeichnet sie. Sie sind bequem zu testen, sie brechen selten. Was statisch ist, ist ziemlich schwer zu brechen, und das Testen ist einfach.

Anwendungen in Kombination mit der Flux-Architektur sind leistungsstark. Wahrscheinlich wissen viele Leute, dass dies wirklich eine mächtige Sache ist. Welche Bedeutung muss erwähnt werden? Neben React Redux gibt es viele weitere Bundles. Und Sie wissen wahrscheinlich, dass es einen zweiten Winkel gibt. Es ist auch eine Kombination aus reaktivem Framework und Flux-Architektur. Vue, Flux Redux — Fluxxor, MobX . . React Redux. Vue, , , React Redux. .



? , React Redux . Vue, . — . — MVC-. . . - React Redux .

MVP/MVVM- . , — , , . single page application, multiple page application. - - . , -, - . , MVP, .

— single page application , , . . Flux React Redux, View, Angular, MobX, Fluxxor . .

. .

> MVC: Smalltalk-80 , General MVC , ASP.NET , MVC on Web
> MVP: MVP vs MVC , GUI Architecture , Backbone , Angular1
> MVVM: MS Silverlight , i-BEM
> Flux: Hexlet , Flux for stupid people , Flux official , ReactJS , VueJS
> : , «Javascript. » , ., « » , D.Garlain, M.Shaw, ”An introduction to Software Architecture” (1994), E.Dijkstra ”GOTO statement considered harmful” (1968)

MVC, MVP, MVVM . , . Flux . , , . , — . . JavaScript. . ES5, «JavaScript. » , ES6- — , , , .

, « ». . Java, . , , Flux, . MVP, — -. , . .

, , « ». , , , , , . «GOTO operator considered harmful». . , .

. . . , - , . , , Flux, , input Flux. — , , - . . , . , . Vielen Dank.

Source: https://habr.com/ru/post/de425611/


All Articles